From 19ff8e5a858d04bb9e4eec8e5edb56b1b98196bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@cs.tu-darmstadt.de> Date: Thu, 24 Oct 2019 23:35:55 +0200 Subject: [PATCH] Improve submission and update forms for AKs as well as underlying model Improve blank and unique constraints of model: - allow blank starting times of slotes to store durations before scheduling and adapt string representation - change unique constraint from name and shortname of AK to unique for each event only Implement handling of tags for submission and update (auto-creation) by using a semicolon-separated text file instead of multiple choice field Implement handling of durations for submission Automatically generate short name Use different forms for submission and update Use special adapted template for AK updates instead of submission template Fix EventSlugMixin for POST requests --- AKModel/locale/de_DE/LC_MESSAGES/django.po | 194 ++++++++++-------- .../migrations/0019_slot_start_optional.py | 18 ++ AKModel/migrations/0020_ak_unique.py | 27 +++ AKModel/models.py | 10 +- AKModel/views.py | 16 +- AKSubmission/forms.py | 62 +++++- .../locale/de_DE/LC_MESSAGES/django.po | 35 +++- .../templates/AKSubmission/ak_edit.html | 22 ++ AKSubmission/views.py | 43 ++-- 9 files changed, 306 insertions(+), 121 deletions(-) create mode 100644 AKModel/migrations/0019_slot_start_optional.py create mode 100644 AKModel/migrations/0020_ak_unique.py create mode 100644 AKSubmission/templates/AKSubmission/ak_edit.html diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po index 6c91a57b..7945c257 100644 --- a/AKModel/locale/de_DE/LC_MESSAGES/django.po +++ b/AKModel/locale/de_DE/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-20 17:51+0000\n" +"POT-Creation-Date: 2019-10-24 21:00+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -11,13 +11,13 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: availability.py:38 models.py:20 models.py:40 models.py:105 models.py:153 -#: models.py:184 models.py:209 +#: availability.py:38 models.py:23 models.py:45 models.py:139 models.py:188 +#: models.py:220 models.py:246 msgid "Event" msgstr "Event" -#: availability.py:39 models.py:41 models.py:106 models.py:154 models.py:185 -#: models.py:210 +#: availability.py:39 models.py:46 models.py:140 models.py:189 models.py:221 +#: models.py:247 msgid "Associated event" msgstr "Zugehöriges Event" @@ -29,7 +29,7 @@ msgstr "Person" msgid "Person whose availability this is" msgstr "Person deren Verfügbarkeit hier abgebildet wird" -#: availability.py:56 models.py:188 models.py:203 +#: availability.py:56 models.py:224 models.py:239 msgid "Room" msgstr "Raum" @@ -37,7 +37,7 @@ msgstr "Raum" msgid "Room whose availability this is" msgstr "Raum dessen Verfügbarkeit hier abgebildet wird" -#: availability.py:65 models.py:157 models.py:202 +#: availability.py:65 models.py:192 models.py:238 msgid "AK" msgstr "AK" @@ -47,7 +47,7 @@ msgstr "AK" msgid "AK whose availability this is" msgstr "Verfügbarkeiten" -#: availability.py:74 models.py:63 +#: availability.py:74 models.py:97 msgid "AK Category" msgstr "AK Kategorie" @@ -63,334 +63,346 @@ msgstr "Verfügbarkeit" msgid "Availabilities" msgstr "Verfügbarkeiten" -#: models.py:9 models.py:58 models.py:74 models.py:89 models.py:103 -#: models.py:120 models.py:177 +#: models.py:12 models.py:92 models.py:108 models.py:123 models.py:137 +#: models.py:154 models.py:213 msgid "Name" msgstr "Name" -#: models.py:10 +#: models.py:13 msgid "Name or iteration of the event" msgstr "Name oder Iteration des Events" -#: models.py:11 +#: models.py:14 #, fuzzy #| msgid "Short Name" msgid "Short Form" msgstr "Kurzer Name" -#: models.py:12 +#: models.py:15 msgid "Short name of letters/numbers/dots/dashes/underscores used in URLs." msgstr "" -#: models.py:13 +#: models.py:16 msgid "Start" msgstr "Start" -#: models.py:13 +#: models.py:16 msgid "Time the event begins" msgstr "Zeit zu der das Event beginnt" -#: models.py:14 +#: models.py:17 msgid "End" msgstr "Ende" -#: models.py:14 +#: models.py:17 msgid "Time the event ends" msgstr "Zeit zu der das Event endet" -#: models.py:15 +#: models.py:18 msgid "Place" msgstr "Ort" -#: models.py:16 +#: models.py:19 msgid "City etc. the event takes place in" msgstr "Stadt o.ä. in der das Event stattfindet" -#: models.py:17 +#: models.py:20 msgid "Active State" msgstr "Aktiver Status" -#: models.py:17 +#: models.py:20 msgid "Marks currently active events" msgstr "Markiert aktuell aktive Events" -#: models.py:21 +#: models.py:24 msgid "Events" msgstr "Events" -#: models.py:35 +#: models.py:38 msgid "Nickname" msgstr "Spitzname" -#: models.py:35 +#: models.py:38 msgid "Name to identify an AK owner by" msgstr "Name durch den eine AK Leitung identifiziert wird" -#: models.py:36 +#: models.py:39 +msgid "Slug" +msgstr "Slug" + +#: models.py:40 +msgid "Slug for URL generation" +msgstr "Slug für URL-Generierung" + +#: models.py:41 msgid "E-Mail Address" msgstr "E-Mail Adresse" -#: models.py:36 +#: models.py:41 msgid "Contact mail" msgstr "Kontakt E-Mail" -#: models.py:37 +#: models.py:42 msgid "Institution" msgstr "Instutution" -#: models.py:37 +#: models.py:42 msgid "Uni etc." msgstr "Universität o.ä." -#: models.py:38 models.py:129 +#: models.py:43 models.py:163 msgid "Web Link" msgstr "Internet Link" -#: models.py:38 +#: models.py:43 msgid "Link to Homepage" msgstr "Link zu Homepage oder Webseite" -#: models.py:44 +#: models.py:49 msgid "AK Owner" msgstr "AK Leitung" -#: models.py:45 +#: models.py:50 msgid "AK Owners" msgstr "AK Leitungen" -#: models.py:58 +#: models.py:92 msgid "Name of the AK Category" msgstr "Name des AK Kategorie" -#: models.py:59 models.py:75 +#: models.py:93 models.py:109 msgid "Color" msgstr "Farbe" -#: models.py:59 models.py:75 +#: models.py:93 models.py:109 msgid "Color for displaying" msgstr "Farbe für die Anzeige" -#: models.py:60 models.py:123 +#: models.py:94 models.py:157 msgid "Description" msgstr "Beschreibung" -#: models.py:60 +#: models.py:94 msgid "Short description of this AK Category" msgstr "Beschreibung der AK-Kategorie" -#: models.py:64 +#: models.py:98 msgid "AK Categories" msgstr "AK Kategorien" -#: models.py:74 +#: models.py:108 msgid "Name of the AK Track" msgstr "Name des AK Tracks" -#: models.py:78 +#: models.py:112 msgid "AK Track" msgstr "AK Track" -#: models.py:79 +#: models.py:113 msgid "AK Tracks" msgstr "AK Tracks" -#: models.py:89 +#: models.py:123 msgid "Name of the AK Tag" msgstr "Name das AK Tags" -#: models.py:92 +#: models.py:126 msgid "AK Tag" msgstr "AK Tag" -#: models.py:93 +#: models.py:127 msgid "AK Tags" msgstr "AK Tags" -#: models.py:103 +#: models.py:137 msgid "Name of the Requirement" msgstr "Name der Anforderung" -#: models.py:109 +#: models.py:143 msgid "AK Requirement" msgstr "AK Anforderung" -#: models.py:110 +#: models.py:144 msgid "AK Requirements" msgstr "AK Anforderungen" -#: models.py:120 +#: models.py:154 msgid "Name of the AK" msgstr "Name des AKs" -#: models.py:121 +#: models.py:155 msgid "Short Name" msgstr "Kurzer Name" -#: models.py:122 +#: models.py:156 msgid "Name displayed in the schedule" msgstr "Name zur Anzeige im AK Plan" -#: models.py:123 +#: models.py:157 msgid "Description of the AK" msgstr "Beschreibung des AKs" -#: models.py:125 +#: models.py:159 msgid "Owners" msgstr "Leitungen" -#: models.py:126 +#: models.py:160 msgid "Those organizing the AK" msgstr "Menschen, die den AK organisieren und halten" -#: models.py:129 +#: models.py:163 msgid "Link to wiki page" msgstr "Link zur Wiki Seite" -#: models.py:131 +#: models.py:165 msgid "Category" msgstr "Kategorie" -#: models.py:132 +#: models.py:166 msgid "Category of the AK" msgstr "Kategorie des AKs" -#: models.py:133 +#: models.py:167 msgid "Tags" msgstr "Tags" -#: models.py:133 +#: models.py:167 msgid "Tags provided by owners" msgstr "Tags, die durch die AK Leitung vergeben wurden" -#: models.py:134 +#: models.py:168 msgid "Track" msgstr "Track" -#: models.py:135 +#: models.py:169 msgid "Track the AK belongs to" msgstr "Track zu dem der AK gehört" -#: models.py:137 +#: models.py:171 msgid "Resolution Intention" msgstr "Resolutionsabsicht" -#: models.py:138 +#: models.py:172 msgid "Intends to submit a resolution" msgstr "Beabsichtigt eine Resolution einzureichen" -#: models.py:139 +#: models.py:173 msgid "Present this AK" msgstr "AK Präsentieren" -#: models.py:139 +#: models.py:174 msgid "Present results of this AK" msgstr "Die Ergebnisse dieses AKs vorstellen" -#: models.py:141 +#: models.py:176 msgid "Requirements" msgstr "Anforderungen" -#: models.py:142 +#: models.py:177 msgid "AK's Requirements" msgstr "Anforderungen des AKs" -#: models.py:144 +#: models.py:179 msgid "Conflicting AKs" msgstr "AK Konflikte" -#: models.py:145 +#: models.py:180 msgid "AKs that conflict and thus must not take place at the same time" msgstr "" "AKs, die Konflikte haben und deshalb nicht gleichzeitig stattfinden dürfen" -#: models.py:146 +#: models.py:181 msgid "Prerequisite AKs" msgstr "Vorausgesetzte AKs" -#: models.py:147 +#: models.py:182 msgid "AKs that should precede this AK in the schedule" msgstr "AKS die im AK Plan vor diesem AK stattfinden müssen" -#: models.py:149 +#: models.py:184 msgid "Internal Notes" msgstr "Interne Notizen" -#: models.py:149 +#: models.py:184 msgid "Notes to organizers" msgstr "Notizen an die Organisator*innen" -#: models.py:151 +#: models.py:186 msgid "Interest" msgstr "Interesse" -#: models.py:151 +#: models.py:186 msgid "Expected number of people" msgstr "Erwartete Personenzahl" -#: models.py:158 +#: models.py:193 msgid "AKs" msgstr "AKs" -#: models.py:177 +#: models.py:213 msgid "Name or number of the room" msgstr "Name oder Nummer des Raums" -#: models.py:178 +#: models.py:214 msgid "Building" msgstr "Gebäude" -#: models.py:179 +#: models.py:215 msgid "Name or number of the building" msgstr "Name oder Nummer des Gebäudes" -#: models.py:180 +#: models.py:216 msgid "Capacity" msgstr "Kapazität" -#: models.py:180 +#: models.py:216 msgid "Maximum number of people" msgstr "Maximale Personenzahl" -#: models.py:181 +#: models.py:217 msgid "Properties" msgstr "Eigenschaften" -#: models.py:182 +#: models.py:218 msgid "AK requirements fulfilled by the room" msgstr "AK Anforderungen, die dieser Raum erfüllt" -#: models.py:189 +#: models.py:225 msgid "Rooms" msgstr "Räume" -#: models.py:202 +#: models.py:238 msgid "AK being mapped" msgstr "AK, der zugeordnet wird" -#: models.py:204 +#: models.py:240 msgid "Room the AK will take place in" msgstr "Raum in dem der AK stattfindet" -#: models.py:205 +#: models.py:241 msgid "Slot Begin" msgstr "Beginn des Slots" -#: models.py:205 +#: models.py:241 msgid "Time and date the slot begins" msgstr "Zeit und Datum zu der der AK beginnt" -#: models.py:206 +#: models.py:243 msgid "Duration" msgstr "Dauer" -#: models.py:207 +#: models.py:244 msgid "Length in hours" msgstr "Länge in Stunden" -#: models.py:213 +#: models.py:250 msgid "AK Slot" msgstr "AK Slot" -#: models.py:214 +#: models.py:251 msgid "AK Slots" msgstr "AK Slot" + +#: models.py:265 +msgid "Not scheduled yet" +msgstr "Noch nicht geplant" diff --git a/AKModel/migrations/0019_slot_start_optional.py b/AKModel/migrations/0019_slot_start_optional.py new file mode 100644 index 00000000..0d04806f --- /dev/null +++ b/AKModel/migrations/0019_slot_start_optional.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-10-24 15:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0018_merge_20191023_2227'), + ] + + operations = [ + migrations.AlterField( + model_name='akslot', + name='start', + field=models.DateTimeField(blank=True, help_text='Time and date the slot begins', null=True, verbose_name='Slot Begin'), + ), + ] diff --git a/AKModel/migrations/0020_ak_unique.py b/AKModel/migrations/0020_ak_unique.py new file mode 100644 index 00000000..ee7fbb09 --- /dev/null +++ b/AKModel/migrations/0020_ak_unique.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.6 on 2019-10-24 19:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0019_slot_start_optional'), + ] + + operations = [ + migrations.AlterField( + model_name='ak', + name='name', + field=models.CharField(help_text='Name of the AK', max_length=256, verbose_name='Name'), + ), + migrations.AlterField( + model_name='ak', + name='short_name', + field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, verbose_name='Short Name'), + ), + migrations.AlterUniqueTogether( + name='ak', + unique_together={('short_name', 'event'), ('name', 'event')}, + ), + ] diff --git a/AKModel/models.py b/AKModel/models.py index 81cb9ca4..690a9411 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -151,8 +151,8 @@ class AKRequirement(models.Model): class AK(models.Model): """ An AK is a slot-based activity to be scheduled during an event. """ - name = models.CharField(max_length=256, unique=True, verbose_name=_('Name'), help_text=_('Name of the AK')) - short_name = models.CharField(max_length=64, unique=True, blank=True, verbose_name=_('Short Name'), + name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK')) + short_name = models.CharField(max_length=64, blank=True, verbose_name=_('Short Name'), help_text=_('Name displayed in the schedule')) description = models.TextField(blank=True, verbose_name=_('Description'), help_text=_('Description of the AK')) @@ -191,6 +191,7 @@ class AK(models.Model): class Meta: verbose_name = _('AK') verbose_name_plural = _('AKs') + unique_together = [('name', 'event'), ('short_name', 'event')] def __str__(self): if self.short_name: @@ -237,7 +238,8 @@ class AKSlot(models.Model): ak = models.ForeignKey(to=AK, on_delete=models.CASCADE, verbose_name=_('AK'), help_text=_('AK being mapped')) room = models.ForeignKey(to=Room, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('Room'), help_text=_('Room the AK will take place in')) - start = models.DateTimeField(verbose_name=_('Slot Begin'), help_text=_('Time and date the slot begins')) + start = models.DateTimeField(verbose_name=_('Slot Begin'), help_text=_('Time and date the slot begins'), + blank=True, null=True) duration = models.DecimalField(max_digits=4, decimal_places=2, default=2, verbose_name=_('Duration'), help_text=_('Length in hours')) @@ -259,4 +261,6 @@ class AKSlot(models.Model): """ Display start time of slot in format weekday + time, e.g. "Fri 14:00" """ + if self.start is None: + return _("Not scheduled yet") return self.start.strftime('%a %H:%M') diff --git a/AKModel/views.py b/AKModel/views.py index 84864063..1ef24635 100644 --- a/AKModel/views.py +++ b/AKModel/views.py @@ -1,4 +1,4 @@ -from django.http import Http404 +from django.shortcuts import get_object_or_404 from AKModel.models import Event @@ -9,14 +9,18 @@ class EventSlugMixin: """ event = None - def get(self, request, *args, **kwargs): + def _load_event(self): # Find event based on event slug - try: - self.event = Event.get_by_slug(self.kwargs.get("event_slug", None)) - except Event.DoesNotExist: - raise Http404 + self.event = get_object_or_404(Event, slug=self.kwargs.get("event_slug", None)) + + def get(self, request, *args, **kwargs): + self._load_event() return super().get(request, *args, **kwargs) + def post(self, request, *args, **kwargs): + self._load_event() + return super().post(request, *args, **kwargs) + def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) # Add event to context (to make it accessible in templates) diff --git a/AKSubmission/forms.py b/AKSubmission/forms.py index 414e4539..2d145419 100644 --- a/AKSubmission/forms.py +++ b/AKSubmission/forms.py @@ -2,6 +2,8 @@ from django import forms from AKModel.models import AK, AKOwner +from django.utils.translation import ugettext_lazy as _ + class AKForm(forms.ModelForm): class Meta: @@ -12,17 +14,18 @@ class AKForm(forms.ModelForm): 'owners', 'description', 'category', - 'tags', 'reso', 'present', 'requirements', 'conflicts', 'prerequisites', 'notes', + 'event' ] widgets = { 'requirements': forms.CheckboxSelectMultiple, + 'event': forms.HiddenInput, } def __init__(self, *args, **kwargs): @@ -32,8 +35,63 @@ class AKForm(forms.ModelForm): self.fields["conflicts"].widget.attrs = {'class': 'chosen-select'} self.fields["prerequisites"].widget.attrs = {'class': 'chosen-select'} + help_tags_addition = _('Separate multiple tags with semicolon') + + # Add text fields for tags + self.fields["tags_raw"] = forms.CharField( + required=False, + label=AK.tags.field.verbose_name, + help_text=f"{AK.tags.field.help_text} ({help_tags_addition})") + + @staticmethod + def _clean_duration(duration): + # Handle different duration formats (h:mm and decimal comma instead of point) + if ":" in duration: + h, m = duration.split(":") + duration = int(h) + int(m) / 60 + if "," in str(duration): + duration = float(duration.replace(",", ".")) + return duration + + def clean(self): + cleaned_data = super().clean() + + # Generate short name if not given + short_name = self.cleaned_data["short_name"] + if len(short_name) == 0: + cleaned_data["short_name"] = ''.join(x for x in self.cleaned_data["name"].title() if x.isalnum()) + + # Get tag names from raw tags + cleaned_data["tag_names"] = [name.strip().lower() for name in cleaned_data["tags_raw"].split(";")] + + # Get durations from raw durations field + if "durations" in cleaned_data: + cleaned_data["durations"] = [self._clean_duration(d) for d in self.cleaned_data["durations"].split()] + return cleaned_data + + +class AKSubmissionForm(AKForm): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Add field for durations + self.fields["durations"] = forms.CharField( + widget=forms.Textarea, + label=_("Duration(s)"), + help_text=_("Enter at least one planned duration (in hours). If your AK should have multiple slots, use multiple lines") + ) + + +class AKEditForm(AKForm): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Add existing tags to tag raw field + self.fields["tags_raw"].initial = "; ".join(str(tag) for tag in self.instance.tags.all()) + -class AKWishForm(AKForm): +class AKWishForm(AKSubmissionForm): class Meta(AKForm.Meta): exclude = ['owners'] diff --git a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po index e6500ad7..25f72410 100644 --- a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po +++ b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-24 14:18+0000\n" +"POT-Creation-Date: 2019-10-24 21:34+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,10 +17,27 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#: forms.py:38 +msgid "Separate multiple tags with semicolon" +msgstr "Mehrere Tags mit Semikolon trennen" + +#: forms.py:80 +msgid "Duration(s)" +msgstr "Dauer(n)" + +#: forms.py:81 +msgid "" +"Enter at least one planned duration (in hours). If your AK should have " +"multiple slots, use multiple lines" +msgstr "" +"Mindestens eine geplante Dauer (in Stunden) angeben. Wenn der AK mehrere " +"Slots haben soll, mehrere Zeilen verwenden" + #: templates/AKSubmission/ak_detail.html:8 #: templates/AKSubmission/ak_detail.html:13 #: templates/AKSubmission/ak_detail.html:18 -#: templates/AKSubmission/ak_list.html:8 templates/AKSubmission/ak_list.html:13 +#: templates/AKSubmission/ak_edit.html:14 templates/AKSubmission/ak_list.html:8 +#: templates/AKSubmission/ak_list.html:13 #: templates/AKSubmission/ak_list.html:18 #: templates/AKSubmission/akowner_create_update.html:13 #: templates/AKSubmission/submission_overview.html:6 @@ -72,6 +89,14 @@ msgstr "Dauer" msgid "Room" msgstr "Raum" +#: templates/AKSubmission/ak_edit.html:8 templates/AKSubmission/ak_edit.html:21 +msgid "Edit AK" +msgstr "AK bearbeiten" + +#: templates/AKSubmission/ak_edit.html:16 +msgid "Edit" +msgstr "Bearbeiten" + #: templates/AKSubmission/ak_list.html:14 msgid "AKs" msgstr "AKs" @@ -163,14 +188,14 @@ msgstr "" msgid "AK successfully created" msgstr "AK erfolgreich angelegt" -#: views.py:149 +#: views.py:151 msgid "AK successfully updated" msgstr "AK erfolgreich bearbeitet" -#: views.py:193 +#: views.py:208 msgid "Person Info successfully updated" msgstr "Personen-Info erfolgreich bearbeitet" -#: views.py:205 +#: views.py:220 msgid "No user selected" msgstr "Keine Person ausgewählt" diff --git a/AKSubmission/templates/AKSubmission/ak_edit.html b/AKSubmission/templates/AKSubmission/ak_edit.html new file mode 100644 index 00000000..45b1f9d3 --- /dev/null +++ b/AKSubmission/templates/AKSubmission/ak_edit.html @@ -0,0 +1,22 @@ +{% extends 'AKSubmission/submit_new.html' %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome %} +{% load staticfiles %} + +{% block title %}{{ event.slug }} - {% trans "Edit AK" %}{% endblock %} + +{% block breadcrumbs %} + <li class="breadcrumb-item"><a href="#">AKPlanning</a></li> + <li class="breadcrumb-item"><a href="#">{{ event.slug }}</a></li> + <li class="breadcrumb-item"><a + href="{% url 'submit:submission_overview' event_slug=event.slug %}">{% trans "AK Submission" %}</a></li> + <li class="breadcrumb-item"><a href="#">{{ ak.short_name }}</a></li> + <li class="breadcrumb-item active">{% trans "Edit" %}</li> +{% endblock %} + + +{% block headline %} + <h2>{% trans 'Edit AK' %}</h2> +{% endblock %} diff --git a/AKSubmission/views.py b/AKSubmission/views.py index 873cc975..b9011f86 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -6,12 +6,12 @@ from django.utils.translation import gettext_lazy as _ from django.views import View from django.views.generic import ListView, DetailView, CreateView, UpdateView -from AKModel.models import AK, AKCategory, AKTag, AKOwner +from AKModel.models import AK, AKCategory, AKTag, AKOwner, AKSlot from AKModel.models import Event from AKModel.views import EventSlugMixin from AKModel.views import FilterByEventSlugMixin -from AKSubmission.forms import AKForm, AKWishForm, AKOwnerForm +from AKSubmission.forms import AKForm, AKWishForm, AKOwnerForm, AKEditForm, AKSubmissionForm from django.conf import settings @@ -99,34 +99,36 @@ class AKListByTagView(AKListView): class AKAndAKWishSubmissionView(EventSlugMixin, CreateView): model = AK template_name = 'AKSubmission/submit_new.html' - form_class = AKForm + form_class = AKSubmissionForm def get_success_url(self): messages.add_message(self.request, messages.SUCCESS, _("AK successfully created")) return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.pk}) def form_valid(self, form): - instance = form.save(commit=False) - - # Set event - instance.event = Event.get_by_slug(self.kwargs["event_slug"]) - - # Generate short name if not given - # TODO + super_form_valid = super().form_valid(form) # Generate wiki link # TODO + # Set tags (and generate them if necessary) + for tag_name in form.cleaned_data["tag_names"]: + tag, _ = AKTag.objects.get_or_create(name=tag_name) + self.object.tags.add(tag) + # Generate slot(s) - # TODO + for duration in form.cleaned_data["durations"]: + new_slot = AKSlot(ak=self.object, duration=duration, event=self.object.event) + new_slot.save() - return super().form_valid(form) + return super_form_valid class AKSubmissionView(AKAndAKWishSubmissionView): def get_initial(self): initials = super(AKAndAKWishSubmissionView, self).get_initial() initials['owners'] = [AKOwner.get_by_slug(self.kwargs['owner_slug'])] + initials['event'] = self.event return initials def get_context_data(self, *, object_list=None, **kwargs): @@ -142,13 +144,26 @@ class AKWishSubmissionView(AKAndAKWishSubmissionView): class AKEditView(EventSlugMixin, UpdateView): model = AK - template_name = 'AKSubmission/submit_new.html' - form_class = AKForm + template_name = 'AKSubmission/ak_edit.html' + form_class = AKEditForm def get_success_url(self): messages.add_message(self.request, messages.SUCCESS, _("AK successfully updated")) return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.pk}) + def form_valid(self, form): + super_form_valid = super().form_valid(form) + + # Detach existing tags + self.object.tags.clear() + + # Set tags (and generate them if necessary) + for tag_name in form.cleaned_data["tag_names"]: + tag, _ = AKTag.objects.get_or_create(name=tag_name) + self.object.tags.add(tag) + + return super_form_valid + class AKOwnerCreateView(EventSlugMixin, CreateView): model = AKOwner -- GitLab