Skip to content

Commit

Permalink
Changed to using ModelForm, still need to fix FileUpload. Also added …
Browse files Browse the repository at this point in the history
…Spreadsheet support.
  • Loading branch information
VebjornNyvoll committed Nov 2, 2023
1 parent a06e740 commit 757a8d6
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 12 deletions.
24 changes: 17 additions & 7 deletions src/make_queue/forms/reservation.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from datetime import datetime

from django import forms
from django.db.models import TextChoices
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _
from django.core.validators import FileExtensionValidator

from news.models import TimePlace
from web.widgets import SemanticChoiceInput
from ..models.machine import Machine, MachineType

from ..models.reservation import SLARequest

class ReservationForm(forms.Form):
"""Form for creating or changing a reservation."""
Expand Down Expand Up @@ -79,7 +79,17 @@ class Owner(TextChoices):
owner = forms.TypedChoiceField(choices=Owner.choices, coerce=Owner)


class SLARequestForm(forms.Form):
description = forms.CharField(widget=forms.Textarea, required=True, label=_("Description"), help_text=_("Provide a description of the object you want us to print and why it should be printed using one of the SLA printers."))
file = forms.FileField(validators=[FileExtensionValidator(allowed_extensions=["stl"])], required=True, label=_("Upload STL"))
final_date = forms.DateField(label=_("Final date"), widget=forms.SelectDateWidget, help_text="This field is not required, but if you have a date you need the object within you may provide it here. We do not guarantee to print it within the chosen date, but if we are unable to print within the selected date we will refrain from printing the object at all to save materials.")
class SLARequestForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea, required=True, label=_("Description"), help_text=_(
"Provide a description of the object you want us to print and why it should be printed using one of the SLA printers."
))
file = forms.FileField(required=True, label=_("Upload STL files"))
final_date = forms.DateField(required=False, widget=forms.DateInput(attrs=dict(type='date', min=datetime.today().strftime('%Y-%m-%d'))),
help_text=_(
"Only provide a date if you will not use the print if it's printed after your selected date. We do not "
"guarantee that your print will be printed within the selected date, but we won't waste material "
"printing it after."), label=_("Final date (optional)"))

class Meta:
model = SLARequest
fields = ['title', 'purpose', 'description', 'file', 'final_date']
31 changes: 30 additions & 1 deletion src/make_queue/models/reservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.db.models import Q, TextChoices
from django.utils import timezone
from django.utils.formats import time_format
from django.utils.text import capfirst
Expand All @@ -18,6 +18,7 @@
from util.model_utils import ComparisonType, comparison_boilerplate
from web.modelfields import UnlimitedCharField
from .machine import Machine, MachineType
from util.storage import UploadToUtils


class Quota(models.Model):
Expand Down Expand Up @@ -482,3 +483,31 @@ def overlap(self, other: 'ReservationRule.Period'):
(other.exact_start_weekday, other.exact_end_weekday)
)
return hours_overlap > 0


class Purpose(TextChoices):
BACHELOR = "Bachelor", "Bachelor's thesis"
MASTER = "Master", "Master's thesis"
PHD = "PhD", "PhD thesis"
ORGANIZATION = "Org", "Student organization"
HOBBY = "Hobby", "Hobby project"
STUDY = "Study", "Other study related project"
OTHER = "Other", "Other project (specify in description)"


class SLARequest(models.Model):
# title = models.CharField(required=True, label=_("Title"))
# purpose = models.CharField(choices=Purpose.choices, initial="Hobby", required=True)
# description = models.CharField(widget=forms.Textarea, required=True, label=_("Description"), help_text=_(
# "Provide a description of the object you want us to print and why it should be printed using one of the SLA printers."))
# file = models.FileField(required=True, label=_("Upload STL files"), upload_to=UploadToUtils.get_pk_prefixed_filename_func('sla-request'))
# final_date = models.DateField(widget=forms.DateInput(attrs=dict(type='date', min=datetime.today().strftime('%Y-%m-%d'))),
# help_text=_(
# "Only provide a date if you will not use the print if it's printed after your selected date. We do not "
# "guarantee that your print will be printed within the selected date, but we won't waste material "
# "printing it after."), label=_("Final date (optional)"))
title = models.CharField(max_length=128)
purpose = models.CharField(choices=Purpose.choices, max_length=256, default="Hobby")
description = models.CharField(max_length=256)
file = models.FileField(upload_to='sla-request')
final_date = models.DateField()
160 changes: 160 additions & 0 deletions src/make_queue/static/make_queue/js/sla_form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Linking `reservation_form.css` is required when linking this script.
* The `var` variables below must also be defined.
*/
// noinspection ES6ConvertVarToLetConst
var maximumDay;
// noinspection ES6ConvertVarToLetConst
var shouldForceNewTime;

const reservations = [];
const reservationRules = [];
let canIgnoreRules = false;

const $startTimeField = $("#start-time");
const $startTimeFieldInput = $startTimeField.find("input");
const $endTimeField = $("#end-time");
const $eventField = $("#event-pk");



function isNonReservedDate(date) {
/**
* Checks if the given date is inside any reservation
*/
for (const reservation of reservations) {
if (date >= reservation.startTime && date < reservation.endTime)
return false;
}
return true;
}

function isCompletelyReserved(start, end) {
/**
* Checks if the given time period is completely reserved (ignores open slots of less than 5 minutes)
*/
const maxDifference = 5 * 60 * 1000;
const reservationsInPeriod = getReservationsInPeriod(start, end);
if (!reservationsInPeriod.length)
return false;
reservationsInPeriod.sort((a, b) => a.startTime - b.startTime);
let currentTime = start;
for (const reservation of reservationsInPeriod) {
if (reservation.startTime > new Date(currentTime.valueOf() + maxDifference))
return false;
currentTime = reservation.endTime;
}
return currentTime >= new Date(end.valueOf() - maxDifference);
}

function getReservationsInPeriod(start, end) {
/**
* Returns all reservations that are at least partially within the given time period.
*/
let reservationsInPeriod = [];
for (const reservation of reservations) {
if ((reservation.startTime <= start && reservation.endTime > start) ||
(reservation.startTime > start && reservation.endTime < end) ||
(reservation.startTime < end && reservation.endTime > end)) {
reservationsInPeriod.push(reservation);
}
}
return reservationsInPeriod;
}

let minDateStartTime = new Date();

$startTimeField.calendar({
minDate: minDateStartTime,
maxDate: maximumDay,
mode: "day",
endCalendar: $endTimeField,
initialDate: new Date($startTimeFieldInput.val()),
firstDayOfWeek: 1,
isDisabled: function (date, mode) {
if (!date)
return true;
/* if (mode === "minute")
return !isNonReservedDate(date);
if (mode === "hour") {
date = new Date(date.valueOf());
date.setMinutes(0, 0, 0);
return isCompletelyReserved(date, new Date(date.valueOf() + 60 * 60 * 1000));
}*/
if (mode === "day") {
date = new Date(date.valueOf());
date.setHours(0, 0, 0, 0);
return isCompletelyReserved(date, new Date(date.valueOf() + 24 * 60 * 60 * 1000));
}
return false;
},
onChange: function (value) {
if (value === undefined)
return true;
const shouldChange = isNonReservedDate(value);
if (shouldChange) {
$endTimeField.calendar("setting", "maxDate", getMaxDateReservation(value));
}
return shouldChange;
},
},
);

$("form").submit(function (event) {
let is_valid = true;
$machineNameDropdown.toggleClass("error-border", false);
$startTimeFieldInput.toggleClass("error-border", false);
$endTimeFieldInput.toggleClass("error-border", false);
$eventField.toggleClass("error-border", false);

if ($machineNameDropdown.dropdown("get value") === "default") {
$machineNameDropdown.toggleClass("error-border", true);
is_valid = false;
}

if ($startTimeField.calendar("get date") === null) {
$startTimeFieldInput.toggleClass("error-border", true);
is_valid = false;
}

if ($endTimeField.calendar("get date") === null) {
$endTimeFieldInput.toggleClass("error-border", true);
is_valid = false;
}

if ($("#event-checkbox input").is(":checked") && $eventField.dropdown("get value") === "") {
$eventField.toggleClass("error-border", true);
is_valid = false;
}

if (!is_valid)
return event.preventDefault();
});

function timeSelectionPopupHTML() {
/**
* Creates a valid popup for the time selection utility in the reservation calendar
*/
const $button = $("<div>").addClass("ui fluid make-bg-yellow button").html(gettext("Choose time"));
$button.on("mousedown touchstart", () => {
$startTimeField.calendar("set date", calendar.getSelectionStartTime());
$endTimeField.calendar("set date", calendar.getSelectionEndTime());
calendar.resetSelection();
});
return $button;
}

const calendar = new ReservationCalendar($(".reservation-calendar"), {
date: new Date(),
machineType: getMachineType(),
machine: getMachine(),
selection: true,
canIgnoreRules: false,
selectionPopupContent: timeSelectionPopupHTML,
});

if ($startTimeField.calendar("get date") !== null) {
calendar.showDate($startTimeField.calendar("get date"));
}

getFutureReservations($machineNameDropdown.dropdown("get value"), shouldForceNewTime);
13 changes: 9 additions & 4 deletions src/make_queue/templates/make_queue/sla_request_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
{% load static %}
{% load i18n %}

{% load datetime_tags %}
{% load string_tags %}




{% block body %}
<form class="ui form text container" action="" method="post" onsubmit="{console.log('test')}">
<form class="ui form text container" action="https://script.google.com/macros/s/AKfycbzl88rTfc80k4T9XX9Vu2Jxl4xcn33DX-KxX7QlStrWFyj-XS_t3Xlq6HqlkC8TgUzh/exec" method="post" onsubmit="{console.log('file uploaded')}">
{% csrf_token %}
<h1 class="ui header">{% trans "Request an SLA print" %}</h1>


{{form}}

<div>
<input class="ui blue submit button" type="submit" name="button" value="{% trans "Send" %}" >
</div>
</form>

</form>
{% endblock body %}

0 comments on commit 757a8d6

Please sign in to comment.