diff --git a/AKModel/forms.py b/AKModel/forms.py index 43dcfa96499660292a6ea58c541f6ca1aece3979..1f5c07eeee2686434674a7b80e7b8aec6d2bab7c 100644 --- a/AKModel/forms.py +++ b/AKModel/forms.py @@ -68,3 +68,7 @@ class NewEventWizardActivateForm(forms.ModelForm): class Meta: fields = ["active"] model = Event + + +class AdminIntermediateForm(forms.Form): + pass diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po index 6e3bc74de86b2df3c5f0acc1e3d65fcfe5fbf0bf..3aefe1d40ecfcdc0e1834df1e4f40a89c6805298 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: 2022-08-17 22:41+0200\n" +"POT-Creation-Date: 2022-09-27 14:14+0200\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" @@ -65,17 +65,17 @@ msgstr "Die eingegebene Verfügbarkeit enthält ein ungültiges Datum." msgid "Please fill in your availabilities!" msgstr "Bitte Verfügbarkeiten eintragen!" -#: .\AKModel\availability\models.py:38 .\AKModel\models.py:53 -#: .\AKModel\models.py:117 .\AKModel\models.py:172 .\AKModel\models.py:191 -#: .\AKModel\models.py:223 .\AKModel\models.py:277 .\AKModel\models.py:343 -#: .\AKModel\models.py:376 .\AKModel\models.py:447 .\AKModel\models.py:488 +#: .\AKModel\availability\models.py:38 .\AKModel\models.py:54 +#: .\AKModel\models.py:120 .\AKModel\models.py:175 .\AKModel\models.py:194 +#: .\AKModel\models.py:226 .\AKModel\models.py:280 .\AKModel\models.py:354 +#: .\AKModel\models.py:387 .\AKModel\models.py:458 .\AKModel\models.py:499 msgid "Event" msgstr "Event" -#: .\AKModel\availability\models.py:39 .\AKModel\models.py:118 -#: .\AKModel\models.py:173 .\AKModel\models.py:192 .\AKModel\models.py:224 -#: .\AKModel\models.py:278 .\AKModel\models.py:344 .\AKModel\models.py:377 -#: .\AKModel\models.py:448 .\AKModel\models.py:489 +#: .\AKModel\availability\models.py:39 .\AKModel\models.py:121 +#: .\AKModel\models.py:176 .\AKModel\models.py:195 .\AKModel\models.py:227 +#: .\AKModel\models.py:281 .\AKModel\models.py:355 .\AKModel\models.py:388 +#: .\AKModel\models.py:459 .\AKModel\models.py:500 msgid "Associated event" msgstr "Zugehöriges Event" @@ -87,8 +87,8 @@ msgstr "Person" msgid "Person whose availability this is" msgstr "Person deren Verfügbarkeit hier abgebildet wird" -#: .\AKModel\availability\models.py:56 .\AKModel\models.py:347 -#: .\AKModel\models.py:366 .\AKModel\models.py:497 +#: .\AKModel\availability\models.py:56 .\AKModel\models.py:358 +#: .\AKModel\models.py:377 .\AKModel\models.py:508 msgid "Room" msgstr "Raum" @@ -96,8 +96,8 @@ msgstr "Raum" msgid "Room whose availability this is" msgstr "Raum dessen Verfügbarkeit hier abgebildet wird" -#: .\AKModel\availability\models.py:65 .\AKModel\models.py:283 -#: .\AKModel\models.py:365 .\AKModel\models.py:442 +#: .\AKModel\availability\models.py:65 .\AKModel\models.py:286 +#: .\AKModel\models.py:376 .\AKModel\models.py:453 msgid "AK" msgstr "AK" @@ -105,8 +105,8 @@ msgstr "AK" msgid "AK whose availability this is" msgstr "Verfügbarkeiten" -#: .\AKModel\availability\models.py:74 .\AKModel\models.py:176 -#: .\AKModel\models.py:503 +#: .\AKModel\availability\models.py:74 .\AKModel\models.py:179 +#: .\AKModel\models.py:514 msgid "AK Category" msgstr "AK-Kategorie" @@ -135,131 +135,131 @@ msgstr "AK-Kategorien kopieren" msgid "Copy ak requirements" msgstr "AK-Anforderungen kopieren" -#: .\AKModel\models.py:17 .\AKModel\models.py:164 .\AKModel\models.py:188 -#: .\AKModel\models.py:207 .\AKModel\models.py:221 .\AKModel\models.py:239 -#: .\AKModel\models.py:335 +#: .\AKModel\models.py:18 .\AKModel\models.py:167 .\AKModel\models.py:191 +#: .\AKModel\models.py:210 .\AKModel\models.py:224 .\AKModel\models.py:242 +#: .\AKModel\models.py:346 msgid "Name" msgstr "Name" -#: .\AKModel\models.py:18 +#: .\AKModel\models.py:19 msgid "Name or iteration of the event" msgstr "Name oder Iteration des Events" -#: .\AKModel\models.py:19 +#: .\AKModel\models.py:20 msgid "Short Form" msgstr "Kurzer Name" -#: .\AKModel\models.py:20 +#: .\AKModel\models.py:21 msgid "Short name of letters/numbers/dots/dashes/underscores used in URLs." msgstr "" "Kurzname bestehend aus Buchstaben, Nummern, Punkten und Unterstrichen zur " "Nutzung in URLs" -#: .\AKModel\models.py:22 +#: .\AKModel\models.py:23 msgid "Place" msgstr "Ort" -#: .\AKModel\models.py:23 +#: .\AKModel\models.py:24 msgid "City etc. the event takes place in" msgstr "Stadt o.ä. in der das Event stattfindet" -#: .\AKModel\models.py:25 +#: .\AKModel\models.py:26 msgid "Time Zone" msgstr "Zeitzone" -#: .\AKModel\models.py:25 +#: .\AKModel\models.py:26 msgid "Time Zone where this event takes place in" msgstr "Zeitzone in der das Event stattfindet" -#: .\AKModel\models.py:26 .\AKModel\views.py:220 +#: .\AKModel\models.py:27 .\AKModel\views.py:242 msgid "Start" msgstr "Start" -#: .\AKModel\models.py:26 +#: .\AKModel\models.py:27 msgid "Time the event begins" msgstr "Zeit zu der das Event beginnt" -#: .\AKModel\models.py:27 +#: .\AKModel\models.py:28 msgid "End" msgstr "Ende" -#: .\AKModel\models.py:27 +#: .\AKModel\models.py:28 msgid "Time the event ends" msgstr "Zeit zu der das Event endet" -#: .\AKModel\models.py:28 +#: .\AKModel\models.py:29 msgid "Resolution Deadline" msgstr "Resolutionsdeadline" -#: .\AKModel\models.py:29 +#: .\AKModel\models.py:30 msgid "When should AKs with intention to submit a resolution be done?" msgstr "Wann sollen AKs mit Resolutionsabsicht stattgefunden haben?" -#: .\AKModel\models.py:31 +#: .\AKModel\models.py:32 msgid "Interest Window Start" msgstr "Beginn Interessensbekundung" -#: .\AKModel\models.py:32 +#: .\AKModel\models.py:33 msgid "Opening time for expression of interest." msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs." -#: .\AKModel\models.py:33 +#: .\AKModel\models.py:34 msgid "Interest Window End" msgstr "Ende Interessensbekundung" -#: .\AKModel\models.py:34 +#: .\AKModel\models.py:35 msgid "Closing time for expression of interest." msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs." -#: .\AKModel\models.py:36 +#: .\AKModel\models.py:37 msgid "Public event" msgstr "Öffentliches Event" -#: .\AKModel\models.py:37 +#: .\AKModel\models.py:38 msgid "Show this event on overview page." msgstr "Zeige dieses Event auf der Übersichtseite an" -#: .\AKModel\models.py:39 +#: .\AKModel\models.py:40 msgid "Active State" msgstr "Aktiver Status" -#: .\AKModel\models.py:39 +#: .\AKModel\models.py:40 msgid "Marks currently active events" msgstr "Markiert aktuell aktive Events" -#: .\AKModel\models.py:40 +#: .\AKModel\models.py:41 msgid "Plan Hidden" msgstr "Plan verborgen" -#: .\AKModel\models.py:40 +#: .\AKModel\models.py:41 msgid "Hides plan for non-staff users" msgstr "Verbirgt den Plan für Nutzer*innen ohne erweiterte Rechte" -#: .\AKModel\models.py:43 +#: .\AKModel\models.py:44 msgid "Base URL" msgstr "URL-Prefix" -#: .\AKModel\models.py:43 +#: .\AKModel\models.py:44 msgid "Prefix for wiki link construction" msgstr "Prefix für die automatische Generierung von Wiki-Links" -#: .\AKModel\models.py:44 +#: .\AKModel\models.py:45 msgid "Wiki Export Template Name" msgstr "Wiki-Export Templatename" -#: .\AKModel\models.py:45 +#: .\AKModel\models.py:46 msgid "Default Slot Length" msgstr "Standardslotlänge" -#: .\AKModel\models.py:46 +#: .\AKModel\models.py:47 msgid "Default length in hours that is assumed for AKs in this event." msgstr "Standardlänge von Slots (in Stunden) für dieses Event" -#: .\AKModel\models.py:48 +#: .\AKModel\models.py:49 msgid "Contact email address" msgstr "E-Mail Kontaktadresse" -#: .\AKModel\models.py:50 +#: .\AKModel\models.py:51 msgid "" "An email address that is displayed on every page and can be used for all " "kinds of questions" @@ -267,75 +267,75 @@ msgstr "" "Eine Mailadresse die auf jeder Seite angezeigt wird und für alle Arten von " "Fragen genutzt werden kann" -#: .\AKModel\models.py:54 +#: .\AKModel\models.py:55 msgid "Events" msgstr "Events" -#: .\AKModel\models.py:112 +#: .\AKModel\models.py:115 msgid "Nickname" msgstr "Spitzname" -#: .\AKModel\models.py:112 +#: .\AKModel\models.py:115 msgid "Name to identify an AK owner by" msgstr "Name, durch den eine AK-Leitung identifiziert wird" -#: .\AKModel\models.py:113 +#: .\AKModel\models.py:116 msgid "Slug" msgstr "Slug" -#: .\AKModel\models.py:113 +#: .\AKModel\models.py:116 msgid "Slug for URL generation" msgstr "Slug für URL-Generierung" -#: .\AKModel\models.py:114 +#: .\AKModel\models.py:117 msgid "Institution" msgstr "Instutution" -#: .\AKModel\models.py:114 +#: .\AKModel\models.py:117 msgid "Uni etc." msgstr "Universität o.ä." -#: .\AKModel\models.py:115 .\AKModel\models.py:248 +#: .\AKModel\models.py:118 .\AKModel\models.py:251 msgid "Web Link" msgstr "Internet Link" -#: .\AKModel\models.py:115 +#: .\AKModel\models.py:118 msgid "Link to Homepage" msgstr "Link zu Homepage oder Webseite" -#: .\AKModel\models.py:121 .\AKModel\models.py:496 +#: .\AKModel\models.py:124 .\AKModel\models.py:507 msgid "AK Owner" msgstr "AK-Leitung" -#: .\AKModel\models.py:122 +#: .\AKModel\models.py:125 msgid "AK Owners" msgstr "AK-Leitungen" -#: .\AKModel\models.py:164 +#: .\AKModel\models.py:167 msgid "Name of the AK Category" msgstr "Name der AK-Kategorie" -#: .\AKModel\models.py:165 .\AKModel\models.py:189 +#: .\AKModel\models.py:168 .\AKModel\models.py:192 msgid "Color" msgstr "Farbe" -#: .\AKModel\models.py:165 .\AKModel\models.py:189 +#: .\AKModel\models.py:168 .\AKModel\models.py:192 msgid "Color for displaying" msgstr "Farbe für die Anzeige" -#: .\AKModel\models.py:166 .\AKModel\models.py:242 +#: .\AKModel\models.py:169 .\AKModel\models.py:245 msgid "Description" msgstr "Beschreibung" -#: .\AKModel\models.py:167 +#: .\AKModel\models.py:170 msgid "Short description of this AK Category" msgstr "Beschreibung der AK-Kategorie" -#: .\AKModel\models.py:168 +#: .\AKModel\models.py:171 msgid "Present by default" msgstr "Defaultmäßig präsentieren" -#: .\AKModel\models.py:170 +#: .\AKModel\models.py:173 msgid "" "Present AKs of this category by default if AK owner did not specify whether " "this AK should be presented?" @@ -343,152 +343,152 @@ msgstr "" "AKs dieser Kategorie standardmäßig vorstellen, wenn die Leitungen das für " "ihren AK nicht explizit spezifiziert haben?" -#: .\AKModel\models.py:177 +#: .\AKModel\models.py:180 msgid "AK Categories" msgstr "AK-Kategorien" -#: .\AKModel\models.py:188 +#: .\AKModel\models.py:191 msgid "Name of the AK Track" msgstr "Name des AK-Tracks" -#: .\AKModel\models.py:195 +#: .\AKModel\models.py:198 msgid "AK Track" msgstr "AK-Track" -#: .\AKModel\models.py:196 +#: .\AKModel\models.py:199 msgid "AK Tracks" msgstr "AK-Tracks" -#: .\AKModel\models.py:207 +#: .\AKModel\models.py:210 msgid "Name of the AK Tag" msgstr "Name das AK-Tags" -#: .\AKModel\models.py:210 +#: .\AKModel\models.py:213 msgid "AK Tag" msgstr "AK-Tag" -#: .\AKModel\models.py:211 +#: .\AKModel\models.py:214 msgid "AK Tags" msgstr "AK-Tags" -#: .\AKModel\models.py:221 +#: .\AKModel\models.py:224 msgid "Name of the Requirement" msgstr "Name der Anforderung" -#: .\AKModel\models.py:227 .\AKModel\models.py:500 +#: .\AKModel\models.py:230 .\AKModel\models.py:511 msgid "AK Requirement" msgstr "AK-Anforderung" -#: .\AKModel\models.py:228 +#: .\AKModel\models.py:231 msgid "AK Requirements" msgstr "AK-Anforderungen" -#: .\AKModel\models.py:239 +#: .\AKModel\models.py:242 msgid "Name of the AK" msgstr "Name des AKs" -#: .\AKModel\models.py:240 +#: .\AKModel\models.py:243 msgid "Short Name" msgstr "Kurzer Name" -#: .\AKModel\models.py:241 +#: .\AKModel\models.py:244 msgid "Name displayed in the schedule" msgstr "Name zur Anzeige im AK-Plan" -#: .\AKModel\models.py:242 +#: .\AKModel\models.py:245 msgid "Description of the AK" msgstr "Beschreibung des AKs" -#: .\AKModel\models.py:244 +#: .\AKModel\models.py:247 msgid "Owners" msgstr "Leitungen" -#: .\AKModel\models.py:245 +#: .\AKModel\models.py:248 msgid "Those organizing the AK" msgstr "Menschen, die den AK organisieren und halten" -#: .\AKModel\models.py:248 +#: .\AKModel\models.py:251 msgid "Link to wiki page" msgstr "Link zur Wiki Seite" -#: .\AKModel\models.py:249 +#: .\AKModel\models.py:252 msgid "Protocol Link" msgstr "Protokolllink" -#: .\AKModel\models.py:249 +#: .\AKModel\models.py:252 msgid "Link to protocol" msgstr "Link zum Protokoll" -#: .\AKModel\models.py:251 +#: .\AKModel\models.py:254 msgid "Category" msgstr "Kategorie" -#: .\AKModel\models.py:252 +#: .\AKModel\models.py:255 msgid "Category of the AK" msgstr "Kategorie des AKs" -#: .\AKModel\models.py:253 +#: .\AKModel\models.py:256 msgid "Tags" msgstr "Tags" -#: .\AKModel\models.py:253 +#: .\AKModel\models.py:256 msgid "Tags provided by owners" msgstr "Tags, die durch die AK-Leitung vergeben wurden" -#: .\AKModel\models.py:254 +#: .\AKModel\models.py:257 msgid "Track" msgstr "Track" -#: .\AKModel\models.py:255 +#: .\AKModel\models.py:258 msgid "Track the AK belongs to" msgstr "Track zu dem der AK gehört" -#: .\AKModel\models.py:257 +#: .\AKModel\models.py:260 msgid "Resolution Intention" msgstr "Resolutionsabsicht" -#: .\AKModel\models.py:258 +#: .\AKModel\models.py:261 msgid "Intends to submit a resolution" msgstr "Beabsichtigt eine Resolution einzureichen" -#: .\AKModel\models.py:259 +#: .\AKModel\models.py:262 msgid "Present this AK" msgstr "AK präsentieren" -#: .\AKModel\models.py:260 +#: .\AKModel\models.py:263 msgid "Present results of this AK" msgstr "Die Ergebnisse dieses AKs vorstellen" -#: .\AKModel\models.py:262 .\AKModel\templates\admin\AKModel\status.html:97 +#: .\AKModel\models.py:265 .\AKModel\templates\admin\AKModel\status.html:97 msgid "Requirements" msgstr "Anforderungen" -#: .\AKModel\models.py:263 +#: .\AKModel\models.py:266 msgid "AK's Requirements" msgstr "Anforderungen des AKs" -#: .\AKModel\models.py:265 +#: .\AKModel\models.py:268 msgid "Conflicting AKs" msgstr "AK-Konflikte" -#: .\AKModel\models.py:266 +#: .\AKModel\models.py:269 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" -#: .\AKModel\models.py:267 +#: .\AKModel\models.py:270 msgid "Prerequisite AKs" msgstr "Vorausgesetzte AKs" -#: .\AKModel\models.py:268 +#: .\AKModel\models.py:271 msgid "AKs that should precede this AK in the schedule" msgstr "AKs die im AK-Plan vor diesem AK stattfinden müssen" -#: .\AKModel\models.py:270 +#: .\AKModel\models.py:273 msgid "Organizational Notes" msgstr "Notizen zur Organisation" -#: .\AKModel\models.py:271 +#: .\AKModel\models.py:274 #, fuzzy #| msgid "" #| "Notes to organizers. These are public. For private notes, please send an " @@ -502,258 +502,258 @@ msgstr "" "Anmerkungen bitte den Button für Direktnachrichten verwenden (nach dem " "Anlegen/Bearbeiten)." -#: .\AKModel\models.py:273 +#: .\AKModel\models.py:276 msgid "Interest" msgstr "Interesse" -#: .\AKModel\models.py:273 +#: .\AKModel\models.py:276 msgid "Expected number of people" msgstr "Erwartete Personenzahl" -#: .\AKModel\models.py:274 +#: .\AKModel\models.py:277 msgid "Interest Counter" msgstr "Interessenszähler" -#: .\AKModel\models.py:275 +#: .\AKModel\models.py:278 msgid "People who have indicated interest online" msgstr "Anzahl Personen, die online Interesse bekundet haben" -#: .\AKModel\models.py:284 .\AKModel\models.py:491 +#: .\AKModel\models.py:287 .\AKModel\models.py:502 #: .\AKModel\templates\admin\AKModel\status.html:49 -#: .\AKModel\templates\admin\AKModel\status.html:56 .\AKModel\views.py:337 +#: .\AKModel\templates\admin\AKModel\status.html:56 .\AKModel\views.py:359 msgid "AKs" msgstr "AKs" -#: .\AKModel\models.py:335 +#: .\AKModel\models.py:346 msgid "Name or number of the room" msgstr "Name oder Nummer des Raums" -#: .\AKModel\models.py:336 +#: .\AKModel\models.py:347 msgid "Location" msgstr "Ort" -#: .\AKModel\models.py:337 +#: .\AKModel\models.py:348 msgid "Name or number of the location" msgstr "Name oder Nummer des Ortes" -#: .\AKModel\models.py:338 +#: .\AKModel\models.py:349 msgid "Capacity" msgstr "Kapazität" -#: .\AKModel\models.py:339 +#: .\AKModel\models.py:350 msgid "Maximum number of people (-1 for unlimited)." msgstr "Maximale Personenzahl (-1 wenn unbeschränkt)." -#: .\AKModel\models.py:340 +#: .\AKModel\models.py:351 msgid "Properties" msgstr "Eigenschaften" -#: .\AKModel\models.py:341 +#: .\AKModel\models.py:352 msgid "AK requirements fulfilled by the room" msgstr "AK-Anforderungen, die dieser Raum erfüllt" -#: .\AKModel\models.py:348 .\AKModel\templates\admin\AKModel\status.html:33 +#: .\AKModel\models.py:359 .\AKModel\templates\admin\AKModel\status.html:33 msgid "Rooms" msgstr "Räume" -#: .\AKModel\models.py:365 +#: .\AKModel\models.py:376 msgid "AK being mapped" msgstr "AK, der zugeordnet wird" -#: .\AKModel\models.py:367 +#: .\AKModel\models.py:378 msgid "Room the AK will take place in" msgstr "Raum in dem der AK stattfindet" -#: .\AKModel\models.py:368 +#: .\AKModel\models.py:379 msgid "Slot Begin" msgstr "Beginn des Slots" -#: .\AKModel\models.py:368 +#: .\AKModel\models.py:379 msgid "Time and date the slot begins" msgstr "Zeit und Datum zu der der AK beginnt" -#: .\AKModel\models.py:370 +#: .\AKModel\models.py:381 msgid "Duration" msgstr "Dauer" -#: .\AKModel\models.py:371 +#: .\AKModel\models.py:382 msgid "Length in hours" msgstr "Länge in Stunden" -#: .\AKModel\models.py:373 +#: .\AKModel\models.py:384 msgid "Scheduling fixed" msgstr "Planung fix" -#: .\AKModel\models.py:374 +#: .\AKModel\models.py:385 msgid "Length and time of this AK should not be changed" msgstr "Dauer und Zeit dieses AKs sollten nicht verändert werden" -#: .\AKModel\models.py:379 +#: .\AKModel\models.py:390 msgid "Last update" msgstr "Letzte Aktualisierung" -#: .\AKModel\models.py:382 +#: .\AKModel\models.py:393 msgid "AK Slot" msgstr "AK-Slot" -#: .\AKModel\models.py:383 .\AKModel\models.py:493 +#: .\AKModel\models.py:394 .\AKModel\models.py:504 msgid "AK Slots" msgstr "AK-Slot" -#: .\AKModel\models.py:405 .\AKModel\models.py:414 +#: .\AKModel\models.py:416 .\AKModel\models.py:425 msgid "Not scheduled yet" msgstr "Noch nicht geplant" -#: .\AKModel\models.py:443 +#: .\AKModel\models.py:454 msgid "AK this message belongs to" msgstr "AK zu dem die Nachricht gehört" -#: .\AKModel\models.py:444 +#: .\AKModel\models.py:455 msgid "Message text" msgstr "Nachrichtentext" -#: .\AKModel\models.py:445 +#: .\AKModel\models.py:456 msgid "Message to the organizers. This is not publicly visible." msgstr "" "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar." -#: .\AKModel\models.py:451 +#: .\AKModel\models.py:462 msgid "AK Orga Message" msgstr "AK-Organachricht" -#: .\AKModel\models.py:452 +#: .\AKModel\models.py:463 msgid "AK Orga Messages" msgstr "AK-Organachrichten" -#: .\AKModel\models.py:461 +#: .\AKModel\models.py:472 msgid "Constraint Violation" msgstr "Constraintverletzung" -#: .\AKModel\models.py:462 .\AKModel\templates\admin\AKModel\status.html:79 +#: .\AKModel\models.py:473 .\AKModel\templates\admin\AKModel\status.html:79 msgid "Constraint Violations" msgstr "Constraintverletzungen" -#: .\AKModel\models.py:466 +#: .\AKModel\models.py:477 msgid "Owner has two parallel slots" msgstr "Leitung hat zwei Slots parallel" -#: .\AKModel\models.py:467 +#: .\AKModel\models.py:478 msgid "AK Slot was scheduled outside the AK's availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeit des AKs platziert" -#: .\AKModel\models.py:468 +#: .\AKModel\models.py:479 msgid "Room has two AK slots scheduled at the same time" msgstr "Raum hat zwei AK Slots gleichzeitig" -#: .\AKModel\models.py:469 +#: .\AKModel\models.py:480 msgid "Room does not satisfy the requirement of the scheduled AK" msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht" -#: .\AKModel\models.py:470 +#: .\AKModel\models.py:481 msgid "AK Slot is scheduled at the same time as an AK listed as a conflict" msgstr "" "AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert" -#: .\AKModel\models.py:471 +#: .\AKModel\models.py:482 msgid "AK Slot is scheduled before an AK listed as a prerequisite" msgstr "AK Slot wurde vor einem als Voraussetzung gelisteten AK platziert" -#: .\AKModel\models.py:473 +#: .\AKModel\models.py:484 msgid "" "AK Slot for AK with intention to submit a resolution is scheduled after " "resolution deadline" msgstr "" "AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert" -#: .\AKModel\models.py:474 +#: .\AKModel\models.py:485 msgid "AK Slot in a category is outside that categories availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeiten seiner Kategorie" -#: .\AKModel\models.py:475 +#: .\AKModel\models.py:486 msgid "Two AK Slots for the same AK scheduled at the same time" msgstr "Zwei AK Slots eines AKs wurden zur selben Zeit platziert" -#: .\AKModel\models.py:476 +#: .\AKModel\models.py:487 msgid "Room does not have enough space for interest in scheduled AK Slot" msgstr "Room hat nicht genug Platz für das Interesse am geplanten AK-Slot" -#: .\AKModel\models.py:477 +#: .\AKModel\models.py:488 msgid "AK Slot is scheduled outside the event's availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeit des Events platziert" -#: .\AKModel\models.py:480 +#: .\AKModel\models.py:491 msgid "Warning" msgstr "Warnung" -#: .\AKModel\models.py:481 +#: .\AKModel\models.py:492 msgid "Violation" msgstr "Verletzung" -#: .\AKModel\models.py:483 +#: .\AKModel\models.py:494 msgid "Type" msgstr "Art" -#: .\AKModel\models.py:484 +#: .\AKModel\models.py:495 msgid "Type of violation, i.e. what kind of constraint was violated" msgstr "Art der Verletzung, gibt an welche Art Constraint verletzt wurde" -#: .\AKModel\models.py:485 +#: .\AKModel\models.py:496 msgid "Level" msgstr "Level" -#: .\AKModel\models.py:486 +#: .\AKModel\models.py:497 msgid "Severity level of the violation" msgstr "Schweregrad der Verletzung" -#: .\AKModel\models.py:492 +#: .\AKModel\models.py:503 msgid "AK(s) belonging to this constraint" msgstr "AK(s), die zu diesem Constraint gehören" -#: .\AKModel\models.py:494 +#: .\AKModel\models.py:505 msgid "AK Slot(s) belonging to this constraint" msgstr "AK Slot(s), die zu diesem Constraint gehören" -#: .\AKModel\models.py:496 +#: .\AKModel\models.py:507 msgid "AK Owner belonging to this constraint" msgstr "AK Leitung(en), die zu diesem Constraint gehören" -#: .\AKModel\models.py:498 +#: .\AKModel\models.py:509 msgid "Room belonging to this constraint" msgstr "Raum, der zu diesem Constraint gehört" -#: .\AKModel\models.py:501 +#: .\AKModel\models.py:512 msgid "AK Requirement belonging to this constraint" msgstr "AK Anforderung, die zu diesem Constraint gehört" -#: .\AKModel\models.py:503 +#: .\AKModel\models.py:514 msgid "AK Category belonging to this constraint" msgstr "AK Kategorie, di zu diesem Constraint gehört" -#: .\AKModel\models.py:505 +#: .\AKModel\models.py:516 msgid "Comment" msgstr "Kommentar" -#: .\AKModel\models.py:505 +#: .\AKModel\models.py:516 msgid "Comment or further details for this violation" msgstr "Kommentar oder weitere Details zu dieser Vereletzung" -#: .\AKModel\models.py:508 +#: .\AKModel\models.py:519 msgid "Timestamp" msgstr "Timestamp" -#: .\AKModel\models.py:508 +#: .\AKModel\models.py:519 msgid "Time of creation" msgstr "Zeitpunkt der ERstellung" -#: .\AKModel\models.py:509 +#: .\AKModel\models.py:520 msgid "Manually Resolved" msgstr "Manuell behoben" -#: .\AKModel\models.py:510 +#: .\AKModel\models.py:521 msgid "Mark this violation manually as resolved" msgstr "Markiere diese Verletzung manuell als behoben" -#: .\AKModel\models.py:537 +#: .\AKModel\models.py:548 #: .\AKModel\templates\admin\AKModel\requirements_overview.html:27 msgid "Details" msgstr "Details" @@ -779,6 +779,17 @@ msgstr "" msgid "Logout" msgstr "Ausloggen" +#: .\AKModel\templates\admin\AKModel\action_intermediate.html:23 +msgid "Confirm" +msgstr "Bestätigen" + +#: .\AKModel\templates\admin\AKModel\action_intermediate.html:27 +#: .\AKModel\templates\admin\AKModel\event_wizard\import.html:24 +#: .\AKModel\templates\admin\AKModel\event_wizard\settings.html:29 +#: .\AKModel\templates\admin\AKModel\event_wizard\start.html:23 +msgid "Cancel" +msgstr "Abbrechen" + #: .\AKModel\templates\admin\AKModel\event_wizard\activate.html:9 #: .\AKModel\templates\admin\AKModel\event_wizard\created_prepare_import.html:9 #: .\AKModel\templates\admin\AKModel\event_wizard\finish.html:9 @@ -794,7 +805,7 @@ msgid "Successfully imported.<br><br>Do you want to activate your event now?" msgstr "Erfolgreich importiert.<br><br>Soll das Event jetzt aktiviert werden?" #: .\AKModel\templates\admin\AKModel\event_wizard\activate.html:27 -#: .\AKModel\views.py:225 +#: .\AKModel\views.py:247 msgid "Finish" msgstr "Abschluss" @@ -821,13 +832,6 @@ msgstr "Fortfahren" msgid "Congratulations. Everything is set up!" msgstr "Herzlichen Glückwunsch. Alles ist eingerichtet!" -#: .\AKModel\templates\admin\AKModel\event_wizard\import.html:24 -#: .\AKModel\templates\admin\AKModel\event_wizard\settings.html:29 -#: .\AKModel\templates\admin\AKModel\event_wizard\start.html:23 -#: .\AKModel\templates\admin\AKModel\message_delete.html:21 -msgid "Cancel" -msgstr "Abbrechen" - #: .\AKModel\templates\admin\AKModel\event_wizard\settings.html:26 msgid "Back" msgstr "Zurück" @@ -844,15 +848,7 @@ msgstr "" msgid "Step" msgstr "Schritt" -#: .\AKModel\templates\admin\AKModel\message_delete.html:7 -msgid "Delete Orga-Messages" -msgstr "Organachrichten löschen" - -#: .\AKModel\templates\admin\AKModel\message_delete.html:10 -msgid "Delete AK Orga Messages" -msgstr "AK-Organachrichten löschen" - -#: .\AKModel\templates\admin\AKModel\message_delete.html:11 +#: .\AKModel\templates\admin\AKModel\message_delete.html:8 #, python-format msgid "" "Are you sure you want to delete all orga messages for %(event)s? This will " @@ -861,10 +857,6 @@ msgstr "" "Sollen wirklich alle Organachrichten für %(event)s gelöscht werden? Dadurch " "werden %(message_count)s Nachricht(en) dauerhaft gelöscht:" -#: .\AKModel\templates\admin\AKModel\message_delete.html:17 -msgid "Delete" -msgstr "Löschen" - #: .\AKModel\templates\admin\AKModel\requirements_overview.html:12 msgid "Requirements Overview" msgstr "Übersicht Anforderungen" @@ -996,86 +988,93 @@ msgstr "Login" msgid "Register" msgstr "Registrieren" -#: .\AKModel\views.py:143 +#: .\AKModel\views.py:144 msgid "Event Status" msgstr "Eventstatus" -#: .\AKModel\views.py:156 +#: .\AKModel\views.py:157 msgid "Requirements for Event" msgstr "Anforderungen für das Event" -#: .\AKModel\views.py:170 +#: .\AKModel\views.py:171 msgid "AK CSV Export" msgstr "AK-CSV-Export" -#: .\AKModel\views.py:184 +#: .\AKModel\views.py:185 msgid "AK Wiki Export" msgstr "AK-Wiki-Export" -#: .\AKModel\views.py:192 .\AKModel\views.py:323 +#: .\AKModel\views.py:193 .\AKModel\views.py:345 msgid "Wishes" msgstr "Wünsche" -#: .\AKModel\views.py:211 +#: .\AKModel\views.py:215 +msgid "Delete AK Orga Messages" +msgstr "AK-Organachrichten löschen" + +#: .\AKModel\views.py:233 msgid "AK Orga Messages successfully deleted" msgstr "AK-Organachrichten erfolgreich gelöscht" -#: .\AKModel\views.py:221 +#: .\AKModel\views.py:243 msgid "Settings" msgstr "Einstellungen" -#: .\AKModel\views.py:222 +#: .\AKModel\views.py:244 msgid "Event created, Prepare Import" msgstr "Event angelegt, Import vorbereiten" -#: .\AKModel\views.py:223 +#: .\AKModel\views.py:245 msgid "Import categories & requirements" msgstr "Kategorien & Anforderungen kopieren" -#: .\AKModel\views.py:224 +#: .\AKModel\views.py:246 #, fuzzy #| msgid "Active State" msgid "Activate?" msgstr "Aktivieren?" -#: .\AKModel\views.py:283 +#: .\AKModel\views.py:305 #, python-format msgid "Copied '%(obj)s'" msgstr "'%(obj)s' kopiert" -#: .\AKModel\views.py:286 +#: .\AKModel\views.py:308 #, python-format msgid "Could not copy '%(obj)s' (%(error)s)" msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)" -#: .\AKModel\views.py:318 +#: .\AKModel\views.py:340 msgid "Symbols" msgstr "Symbole" -#: .\AKModel\views.py:319 +#: .\AKModel\views.py:341 msgid "Who?" msgstr "Wer?" -#: .\AKModel\views.py:320 +#: .\AKModel\views.py:342 msgid "Duration(s)" msgstr "Dauer(n)" -#: .\AKModel\views.py:321 +#: .\AKModel\views.py:343 msgid "Reso intention?" msgstr "Resolutionsabsicht?" -#: .\AKModel\views.py:322 +#: .\AKModel\views.py:344 msgid "Category (for Wishes)" msgstr "Kategorie (für Wünsche)" +#~ msgid "Delete Orga-Messages" +#~ msgstr "Organachrichten löschen" + +#~ msgid "Delete" +#~ msgstr "Löschen" + #~ msgid "AK Slot is scheduled in a room with less space than interest" #~ msgstr "" #~ "AK Slot wurde in einem Raum mit weniger Plätzen als am AK Interessierten " #~ "platziert" -#~ msgid "Confirm" -#~ msgstr "Bestätigen" - #~ msgid "messages will be permanently deleted:" #~ msgstr "Nachrichten werden dauerhaft gelöscht:" diff --git a/AKModel/models.py b/AKModel/models.py index 7f82cbd6ec510736265d6238a39417327c936675..ef86329edd234ac32bd909cc81402df1b69ef901 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -2,6 +2,7 @@ import itertools from datetime import timedelta from django.db import models +from django.db.models import Count from django.urls import reverse_lazy from django.utils import timezone from django.utils.datetime_safe import datetime @@ -105,6 +106,12 @@ class Event(models.Model): categories_with_aks.append((category, ak_list)) return categories_with_aks + def get_unscheduled_wish_slots(self): + return self.akslot_set.filter(start__isnull=True).annotate(Count('ak__owners')).filter(ak__owners__count=0) + + def get_aks_without_availabilities(self): + return self.ak_set.annotate(Count('availabilities', distinct=True)).annotate(Count('owners', distinct=True)).filter(availabilities__count=0, owners__count__gt=0) + class AKOwner(models.Model): """ An AKOwner describes the person organizing/holding an AK. diff --git a/AKModel/templates/admin/AKModel/action_intermediate.html b/AKModel/templates/admin/AKModel/action_intermediate.html new file mode 100644 index 0000000000000000000000000000000000000000..0c211ecbb2c5aac5fcf4cdade3e636c56832db4e --- /dev/null +++ b/AKModel/templates/admin/AKModel/action_intermediate.html @@ -0,0 +1,30 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} + + +{% block title %}{{event}}: {{ title }}{% endblock %} + +{% block content %} + {% block action_preview %} + <p> + {{ preview|linebreaksbr }} + </p> + {% endblock %} + + <form method="post">{% csrf_token %} + {% bootstrap_form form %} + + <div class="float-right"> + <button type="submit" class="save btn btn-success" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Confirm" %} + </button> + </div> + <a href="javascript:history.back()" class="btn btn-info"> + {% fa5_icon "times" 'fas' %} {% trans "Cancel" %} + </a> + </form> +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/message_delete.html b/AKModel/templates/admin/AKModel/message_delete.html index 03b5899b8a1a1598f17a7094b3c896b73e4fe80e..1bdbf0a55651360f859b861a3913ae2bd9720c8e 100644 --- a/AKModel/templates/admin/AKModel/message_delete.html +++ b/AKModel/templates/admin/AKModel/message_delete.html @@ -1,24 +1,11 @@ -{% extends "admin/base_site.html" %} +{% extends "admin/AKModel/action_intermediate.html" %} {% load tags_AKModel %} {% load i18n %} {% load fontawesome_5 %} -{% block title %}{{event}}: {% trans "Delete Orga-Messages" %}{% endblock %} - -{% block content %} - <h2>{% trans "Delete AK Orga Messages" %}</h2> +{% block action_preview %} <p>{% blocktrans with message_count=ak_messages.count %}Are you sure you want to delete all orga messages for {{ event }}? This will permanently delete {{ message_count }} message(s):{% endblocktrans %}</p> {% include "admin/AKModel/render_ak_messages.html" %} - - <form method="post">{% csrf_token %} - <button type="submit" class="save btn btn-danger float-right" value="Confirm"> - {% fa5_icon "check" 'fas' %} {% trans "Delete" %} - </button> - - <a href="{% url 'admin:event_status' slug=event.slug %}" class="btn btn-info"> - {% fa5_icon "times" 'fas' %} {% trans "Cancel" %} - </a> - </form> {% endblock %} diff --git a/AKModel/templates/admin/AKModel/status.html b/AKModel/templates/admin/AKModel/status.html index f64a5a0ce3319fd1d85c8a33c2b9def86971b254..362c72406804e4973d9600363511aac46226bbe4 100644 --- a/AKModel/templates/admin/AKModel/status.html +++ b/AKModel/templates/admin/AKModel/status.html @@ -115,7 +115,7 @@ <div class="col-md-4"> <h3 class="block-header">{% trans "Messages" %}</h3> {% include "admin/AKModel/render_ak_messages.html" %} - <a class="btn btn-danger" href="{% url 'admin:ak_delete_orga_messages' slug=event.slug %}">{% trans "Delete all messages" %}</a> + <a class="btn btn-danger" href="{% url 'admin:ak_delete_orga_messages' event_slug=event.slug %}">{% trans "Delete all messages" %}</a> </div> </div> {% endtimezone %} diff --git a/AKModel/urls.py b/AKModel/urls.py index 2071acc9edc56b506eb307f42654e9da1ba82c63..ca9cfe6745aa9321db95561536d1bc42cad13fb6 100644 --- a/AKModel/urls.py +++ b/AKModel/urls.py @@ -79,7 +79,7 @@ def get_admin_urls_event(admin_site): name="ak_csv_export"), path('<slug:slug>/ak-wiki-export/', admin_site.admin_view(AKWikiExportView.as_view()), name="ak_wiki_export"), - path('<slug:slug>/delete-orga-messages/', admin_site.admin_view(AKMessageDeleteView.as_view()), + path('<slug:event_slug>/delete-orga-messages/', admin_site.admin_view(AKMessageDeleteView.as_view()), name="ak_delete_orga_messages"), path('<slug:event_slug>/ak-slide-export/', export_slides, name="ak_slide_export"), diff --git a/AKModel/views.py b/AKModel/views.py index 2729bdb6c47aecfba4077447b334390cf2062906..08f054f14f9812dbec9cf61db67703c700d92db0 100644 --- a/AKModel/views.py +++ b/AKModel/views.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod from itertools import zip_longest from django.contrib import admin, messages @@ -11,7 +12,7 @@ from django_tex.shortcuts import render_to_pdf from rest_framework import viewsets, permissions, mixins from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \ - NewEventWizardImportForm, NewEventWizardActivateForm + NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage, AKRequirement from AKModel.serializers import AKSerializer, AKSlotSerializer, RoomSerializer, AKTrackSerializer, AKCategorySerializer, \ AKOwnerSerializer @@ -194,22 +195,43 @@ class AKWikiExportView(AdminViewMixin, DetailView): return context -class AKMessageDeleteView(AdminViewMixin, DeleteView): - model = Event +class IntermediateAdminView(AdminViewMixin, FormView, ABC): + template_name = "admin/AKModel/action_intermediate.html" + form_class = AdminIntermediateForm + + @abstractmethod + def get_preview(self): + pass + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["title"] = self.title + context["preview"] = self.get_preview() + return context + + +class AKMessageDeleteView(EventSlugMixin, IntermediateAdminView): template_name = "admin/AKModel/message_delete.html" + title = _("Delete AK Orga Messages") def get_orga_messages_for_event(self, event): return AKOrgaMessage.objects.filter(ak__event=event) + def get_preview(self): + return None + + def get_success_url(self): + return reverse_lazy('admin:event_status', kwargs={'slug': self.event.slug}) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["ak_messages"] = self.get_orga_messages_for_event(self.get_object()) + context["ak_messages"] = self.get_orga_messages_for_event(self.event) return context - def post(self, request, *args, **kwargs): - self.get_orga_messages_for_event(self.get_object()).delete() + def form_valid(self, form): + self.get_orga_messages_for_event(self.event).delete() messages.add_message(self.request, messages.SUCCESS, _("AK Orga Messages successfully deleted")) - return HttpResponseRedirect(reverse_lazy('admin:event_status', kwargs={'slug': self.get_object().slug})) + return super().form_valid(form) class WizardViewMixin: diff --git a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po index 5729c21831745f43e1246b95031174cbd44bb2ae..ceb03d7f640b6ca44ca57fd8442ef16bf2a99c6e 100644 --- a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po +++ b/AKScheduling/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: 2022-08-17 22:41+0200\n" +"POT-Creation-Date: 2022-09-27 17:59+0200\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" @@ -79,7 +79,7 @@ msgstr "Seit" #: .\AKScheduling\templates\admin\AKScheduling\constraint_violations.html:139 #: .\AKScheduling\templates\admin\AKScheduling\manage_tracks.html:243 #: .\AKScheduling\templates\admin\AKScheduling\scheduling.html:208 -#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:43 +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:48 #: .\AKScheduling\templates\admin\AKScheduling\unscheduled.html:34 msgid "Event Status" msgstr "Event-Status" @@ -158,10 +158,18 @@ msgid "AKs without availabilities" msgstr "AKs ohne Verfügbarkeiten" #: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:28 +msgid "Create default availabilities" +msgstr "Standardverfügbarkeiten anlegen" + +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:31 msgid "AK wishes with slots" msgstr "AK-Wünsche mit Slots" -#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:35 +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:38 +msgid "Delete slots for wishes" +msgstr "" + +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:40 msgid "AKs without slots" msgstr "AKs ohne Slots" @@ -173,10 +181,57 @@ msgstr "Noch nicht geschedulte AK-Slots" msgid "Count" msgstr "Anzahl" -#: .\AKScheduling\views.py:103 +#: .\AKScheduling\views.py:109 msgid "Interest updated" msgstr "Interesse aktualisiert" -#: .\AKScheduling\views.py:141 +#: .\AKScheduling\views.py:147 msgid "Wishes" msgstr "Wünsche" + +#: .\AKScheduling\views.py:155 +msgid "Cleanup: Delete unscheduled slots for wishes" +msgstr "Aufräumen: Noch nicht geplante Slots für Wünsche löschen" + +#: .\AKScheduling\views.py:162 +#, python-brace-format +msgid "" +"The following {count} unscheduled slots of wishes will be deleted:\n" +"\n" +" {slots}" +msgstr "" +"Die folgenden {count} noch nicht geplanten Slots von Wünschen werden " +"gelöscht:\n" +"\n" +" {slots}" + +#: .\AKScheduling\views.py:169 +msgid "Unscheduled slots for wishes successfully deleted" +msgstr "Noch nicht geplante Slots für Wünsche erfolgreich gelöscht" + +#: .\AKScheduling\views.py:174 +msgid "Create default availabilities for AKs" +msgstr "Standardverfügbarkeiten für AKs anlegen" + +#: .\AKScheduling\views.py:181 +#, python-brace-format +msgid "" +"The following {count} AKs don't have any availability information. Create " +"default availability for them:\n" +"\n" +" {aks}" +msgstr "" +"Die folgenden {count} AKs haben keine Verfügbarkeitsinformationen. " +"Standardverfügbarkeiten für sie anlegen:\n" +"\n" +" {aks}" + +#: .\AKScheduling\views.py:199 +#, python-brace-format +msgid "Could not create default availabilities for AK: {ak}" +msgstr "Konnte keine Verfügbarkeit anlegen für AK: {ak}" + +#: .\AKScheduling\views.py:204 +#, python-brace-format +msgid "Created default availabilities for {count} AKs" +msgstr "Standardverfügbarkeiten für {count} AKs angelegt" diff --git a/AKScheduling/models.py b/AKScheduling/models.py index cabf78e16e38fd5e14b4383958244596fc935ddd..6664a8aee83ddf108b04666a5e99a5fea077b4e7 100644 --- a/AKScheduling/models.py +++ b/AKScheduling/models.py @@ -157,7 +157,7 @@ def ak_owners_changed_handler(sender, instance: AK, action: str, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{owner} has the following conflicts: {new_violations}") + #print(f"{owner} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -203,7 +203,7 @@ def ak_conflicts_changed_handler(sender, instance: AK, action: str, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -249,7 +249,7 @@ def ak_prerequisites_changed_handler(sender, instance: AK, action: str, **kwargs c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -298,7 +298,7 @@ def ak_requirements_changed_handler(sender, instance: AK, action: str, **kwargs) c.ak_slots_tmp.add(slot) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -310,7 +310,7 @@ def ak_requirements_changed_handler(sender, instance: AK, action: str, **kwargs) @receiver(post_save, sender=AKSlot) def akslot_changed_handler(sender, instance: AKSlot, **kwargs): # Changes might affect: Duplicate parallel, Two in room, Resodeadline - print(f"{sender} changed") + # print(f"{sender} changed") event = instance.event # == Check for two parallel slots by one of the owners == @@ -341,7 +341,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{owner} has the following conflicts: {new_violations}") + # print(f"{owner} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -373,7 +373,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"Multiple slots in room {instance.room}: {new_violations}") + # print(f"Multiple slots in room {instance.room}: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the slot that was recently changed (important!) @@ -437,7 +437,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(instance) new_violations.append(c) - print(f"{instance.ak} has the following slots outside availabilities: {new_violations}") + # print(f"{instance.ak} has the following slots outside availabilities: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -470,7 +470,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(instance) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -502,7 +502,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -534,7 +534,7 @@ def akslot_changed_handler(sender, instance: AKSlot, **kwargs): c.ak_slots_tmp.add(other_slot) new_violations.append(c) - print(f"{instance} has the following conflicts: {new_violations}") + # print(f"{instance} has the following conflicts: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) @@ -556,7 +556,7 @@ def akslot_deleted_handler(sender, instance: AKSlot, **kwargs): # Manually clean up or remove constraint violations that belong to this slot since there is no cascade deletion # for many2many relationships. Explicitly listening for AK deletion signals is not necessary since they will # transitively trigger this signal and we always set both AK and AKSlot references in a constraint violation - print(f"{instance} deleted") + # print(f"{instance} deleted") for cv in instance.constraintviolation_set.all(): # Make sure not delete CVs that e.g., show three parallel slots in a single room @@ -599,7 +599,7 @@ def room_requirements_changed_handler(sender, instance: Room, action: str, **kwa @receiver(post_save, sender=Availability) def availability_changed_handler(sender, instance: Availability, **kwargs): # Changes might affect: category availability, AK availability, Room availability - print(f"{instance} changed") + # print(f"{instance} changed") event = instance.event @@ -627,7 +627,7 @@ def availability_changed_handler(sender, instance: Availability, **kwargs): c.ak_slots_tmp.add(slot) new_violations.append(c) - print(f"{instance.ak} has the following slots outside availabilities: {new_violations}") + # print(f"{instance.ak} has the following slots outside availabilities: {new_violations}") # ... and compare to/update list of existing violations of this type # belonging to the AK that was recently changed (important!) diff --git a/AKScheduling/templates/admin/AKScheduling/special_attention.html b/AKScheduling/templates/admin/AKScheduling/special_attention.html index 8977c199029459975be657ac07fedb012f2238cc..44d2ced14900b383ee9034cc00eb8b1ffe0a6553 100644 --- a/AKScheduling/templates/admin/AKScheduling/special_attention.html +++ b/AKScheduling/templates/admin/AKScheduling/special_attention.html @@ -22,21 +22,26 @@ {% for ak in aks_without_availabilities %} <a href="{% url "submit:ak_edit" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a><br> {% empty %} - - + -<br> {% endfor %} + <a class="btn btn-warning mt-2" href="{% url "admin:autocreate-availabilities" event_slug=event.slug %}">{% trans "Create default availabilities" %}</a> + + <h4 class="mt-4 mb-4">{% trans "AK wishes with slots" %}</h4> {% for ak in ak_wishes_with_slots %} - <a href="{% url "submit:ak_detail" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a><br> + <a href="{% url "submit:ak_detail" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a> <a href="{% url "admin:AKModel_akslot_changelist" %}?ak={{ ak.pk }}">({{ ak.akslot__count }})</a><br> {% empty %} - - + -<br> {% endfor %} + <a class="btn btn-warning mt-2" href="{% url "admin:cleanup-wish-slots" event_slug=event.slug %}">{% trans "Delete slots for wishes" %}</a> + <h4 class="mt-4 mb-4">{% trans "AKs without slots" %}</h4> {% for ak in aks_without_slots %} <a href="{% url "submit:ak_detail" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a><br> {% empty %} - - + -<br> {% endfor %} <div class="mt-5"> diff --git a/AKScheduling/urls.py b/AKScheduling/urls.py index e0fc27f58b6a236d619a8a06e46a6579ab1572d9..1db4c182b9ab8d135a9217196a2c4596d555e38b 100644 --- a/AKScheduling/urls.py +++ b/AKScheduling/urls.py @@ -1,7 +1,8 @@ from django.urls import path from AKScheduling.views import SchedulingAdminView, UnscheduledSlotsAdminView, TrackAdminView, \ - ConstraintViolationsAdminView, SpecialAttentionAKsAdminView, InterestEnteringAdminView + ConstraintViolationsAdminView, SpecialAttentionAKsAdminView, InterestEnteringAdminView, WishSlotCleanupView, \ + AvailabilityAutocreateView def get_admin_urls_scheduling(admin_site): @@ -14,6 +15,10 @@ def get_admin_urls_scheduling(admin_site): name="constraint-violations"), path('<slug:slug>/special-attention/', admin_site.admin_view(SpecialAttentionAKsAdminView.as_view()), name="special-attention"), + path('<slug:event_slug>/cleanup-wish-slots/', admin_site.admin_view(WishSlotCleanupView.as_view()), + name="cleanup-wish-slots"), + path('<slug:event_slug>/autocreate-availabilities/', admin_site.admin_view(AvailabilityAutocreateView.as_view()), + name="autocreate-availabilities"), path('<slug:event_slug>/tracks/', admin_site.admin_view(TrackAdminView.as_view()), name="tracks_manage"), path('<slug:event_slug>/enter-interest/<int:pk>', admin_site.admin_view(InterestEnteringAdminView.as_view()), diff --git a/AKScheduling/views.py b/AKScheduling/views.py index 47781cf09759413509c7c517bc79ee0aaf00025f..3b40d07cb68c486e73326bccf51eaf06bdc93091 100644 --- a/AKScheduling/views.py +++ b/AKScheduling/views.py @@ -1,9 +1,12 @@ +from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin +from django.db.models import Count +from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView, DetailView, UpdateView from AKModel.models import AKSlot, AKTrack, Event, AK, AKCategory -from AKModel.views import AdminViewMixin, FilterByEventSlugMixin, EventSlugMixin +from AKModel.views import AdminViewMixin, FilterByEventSlugMixin, EventSlugMixin, IntermediateAdminView from AKScheduling.forms import AKInterestForm @@ -71,7 +74,7 @@ class SpecialAttentionAKsAdminView(AdminViewMixin, DetailView): context = super().get_context_data(**kwargs) context["title"] = f"{_('AKs requiring special attention for')} {context['event']}" - aks = AK.objects.filter(event=context["event"]) + aks = AK.objects.filter(event=context["event"]).annotate(Count('owners', distinct=True)).annotate(Count('akslot', distinct=True)).annotate(Count('availabilities', distinct=True)) aks_with_comment = [] ak_wishes_with_slots = [] aks_without_availabilities = [] @@ -81,13 +84,13 @@ class SpecialAttentionAKsAdminView(AdminViewMixin, DetailView): if ak.notes != "": aks_with_comment.append(ak) - if ak.wish: - if ak.akslot_set.count() > 0: + if ak.owners__count == 0: + if ak.akslot__count > 0: ak_wishes_with_slots.append(ak) else: - if ak.akslot_set.count() == 0: + if ak.akslot__count == 0: aks_without_slots.append(ak) - if ak.availabilities.count() == 0: + if ak.availabilities__count == 0: aks_without_availabilities.append(ak) context["aks_with_comment"] = aks_with_comment @@ -153,3 +156,58 @@ class InterestEnteringAdminView(SuccessMessageMixin, AdminViewMixin, EventSlugMi context["categories_with_aks"] = categories_with_aks return context + + +class WishSlotCleanupView(EventSlugMixin, IntermediateAdminView): + title = _('Cleanup: Delete unscheduled slots for wishes') + + def get_success_url(self): + return reverse_lazy('admin:special-attention', kwargs={'slug': self.event.slug}) + + def get_preview(self): + slots = self.event.get_unscheduled_wish_slots() + return _("The following {count} unscheduled slots of wishes will be deleted:\n\n {slots}").format( + count=len(slots), + slots=", ".join(str(s.ak) for s in slots) + ) + + def form_valid(self, form): + self.event.get_unscheduled_wish_slots().delete() + messages.add_message(self.request, messages.SUCCESS, _("Unscheduled slots for wishes successfully deleted")) + return super().form_valid(form) + + +class AvailabilityAutocreateView(EventSlugMixin, IntermediateAdminView): + title = _('Create default availabilities for AKs') + + def get_success_url(self): + return reverse_lazy('admin:special-attention', kwargs={'slug': self.event.slug}) + + def get_preview(self): + aks = self.event.get_aks_without_availabilities() + return _("The following {count} AKs don't have any availability information. " + "Create default availability for them:\n\n {aks}").format( + count=len(aks), + aks=", ".join(str(ak) for ak in aks) + ) + + def form_valid(self, form): + from AKModel.availability.models import Availability + + success_count = 0 + for ak in self.event.get_aks_without_availabilities(): + try: + availability = Availability.with_event_length(event=self.event, ak=ak) + availability.save() + success_count += 1 + except: + messages.add_message( + self.request, messages.WARNING, + _("Could not create default availabilities for AK: {ak}").format(ak=ak) + ) + + messages.add_message( + self.request, messages.SUCCESS, + _("Created default availabilities for {count} AKs").format(count=success_count) + ) + return super().form_valid(form) diff --git a/AKSubmission/forms.py b/AKSubmission/forms.py index e24e0a41f41d4a3625a9b0c421ac0d959e5feeb0..55959be4be524a2d801ac8fd8c51925b48098101 100644 --- a/AKSubmission/forms.py +++ b/AKSubmission/forms.py @@ -151,7 +151,7 @@ class AKEditForm(AKForm): self.fields["tags_raw"].initial = "; ".join(str(tag) for tag in self.instance.tags.all()) -class AKWishForm(AKSubmissionForm): +class AKWishForm(AKForm): class Meta(AKForm.Meta): exclude = ['owners', 'link', 'protocol_link'] diff --git a/AKSubmission/templates/AKSubmission/ak_detail.html b/AKSubmission/templates/AKSubmission/ak_detail.html index 69324b6349e693c8c04fb7b098573f4ed4c5d02c..e5052faf507aeec00ee546ab0e02f14082c700b6 100644 --- a/AKSubmission/templates/AKSubmission/ak_detail.html +++ b/AKSubmission/templates/AKSubmission/ak_detail.html @@ -235,95 +235,96 @@ <p style="margin-top: 30px;margin-bottom: 30px;">{{ ak.description|linebreaks }}</p> - - <table class="table"> - <thead> - <tr> - {% if not ak.event.plan_hidden or user.is_staff %} - <th>{% trans "When?" %}</th> - {% endif %} - <th>{% trans "Duration" %}</th> - {% if not ak.event.plan_hidden or user.is_staff %} - <th>{% trans "Room" %}</th> - {% endif %} - <th></th> - </tr> - </thead> - <tbody> - {% for slot in ak.akslot_set.all %} + {% if not ak.wish %} + <table class="table"> + <thead> <tr> {% if not ak.event.plan_hidden or user.is_staff %} - <td>{{ slot.time_simplified }}</td> + <th>{% trans "When?" %}</th> {% endif %} - <td>{{ slot.duration_simplified }}</td> + <th>{% trans "Duration" %}</th> {% if not ak.event.plan_hidden or user.is_staff %} - <td> - {% if slot.room %} - {% if "AKPlan"|check_app_installed %} - <a href="{% url 'plan:plan_room' event_slug=ak.event.slug pk=slot.room.pk %}">{{ slot.room }}</a> + <th>{% trans "Room" %}</th> + {% endif %} + <th></th> + </tr> + </thead> + <tbody> + {% for slot in ak.akslot_set.all %} + <tr> + {% if not ak.event.plan_hidden or user.is_staff %} + <td>{{ slot.time_simplified }}</td> + {% endif %} + <td>{{ slot.duration_simplified }}</td> + {% if not ak.event.plan_hidden or user.is_staff %} + <td> + {% if slot.room %} + {% if "AKPlan"|check_app_installed %} + <a href="{% url 'plan:plan_room' event_slug=ak.event.slug pk=slot.room.pk %}">{{ slot.room }}</a> + {% else %} + {{ slot.room }} + {% endif %} {% else %} - {{ slot.room }} + - {% endif %} + </td> + {% endif %} + <td> + {% if not slot.start %} + <a href="{% url 'submit:akslot_edit' event_slug=ak.event.slug pk=slot.pk %}" + data-toggle="tooltip" title="{% trans 'Edit' %}" + class="btn btn-success">{% fa5_icon 'pencil-alt' 'fas' %}</a> + <a href="{% url 'submit:akslot_delete' event_slug=ak.event.slug pk=slot.pk %}" + data-toggle="tooltip" title="{% trans 'Delete' %}" + class="btn btn-danger">{% fa5_icon 'times' 'fas' %}</a> {% else %} - - + {% if "AKOnline"|check_app_installed and slot.room and slot.room.virtualroom and slot.room.virtualroom.url != '' %} + <a class="btn btn-success" href="{{ slot.room.virtualroom.url }}"> + {% fa5_icon 'external-link-alt' 'fas' %} {% trans "Go to virtual room" %} + </a> + {% endif %} {% endif %} - </td> - {% endif %} - <td> - {% if not slot.start %} - <a href="{% url 'submit:akslot_edit' event_slug=ak.event.slug pk=slot.pk %}" - data-toggle="tooltip" title="{% trans 'Edit' %}" - class="btn btn-success">{% fa5_icon 'pencil-alt' 'fas' %}</a> - <a href="{% url 'submit:akslot_delete' event_slug=ak.event.slug pk=slot.pk %}" - data-toggle="tooltip" title="{% trans 'Delete' %}" - class="btn btn-danger">{% fa5_icon 'times' 'fas' %}</a> - {% else %} - {% if "AKOnline"|check_app_installed and slot.room and slot.room.virtualroom and slot.room.virtualroom.url != '' %} - <a class="btn btn-success" href="{{ slot.room.virtualroom.url }}"> - {% fa5_icon 'external-link-alt' 'fas' %} {% trans "Go to virtual room" %} - </a> + {% if user.is_staff %} + <a href="{% url 'admin:AKModel_akslot_change' slot.pk %}" + data-toggle="tooltip" title="{% trans 'Schedule' %}" + class="btn btn-outline-success">{% fa5_icon 'stream' 'fas' %}</a> {% endif %} - {% endif %} - {% if user.is_staff %} - <a href="{% url 'admin:AKModel_akslot_change' slot.pk %}" - data-toggle="tooltip" title="{% trans 'Schedule' %}" - class="btn btn-outline-success">{% fa5_icon 'stream' 'fas' %}</a> - {% endif %} - </td> - </tr> - {% endfor %} - </tbody> - </table> + </td> + </tr> + {% endfor %} + </tbody> + </table> - {% if ak.event.active %} - <div class=""> - <a href="{% url 'submit:akslot_add' event_slug=ak.event.slug pk=ak.pk %}" - class="btn btn-success">{% fa5_icon 'plus' 'fas' %} {% trans "Add another slot" %}</a> - </div> - {% endif %} + {% if ak.event.active %} + <div class=""> + <a href="{% url 'submit:akslot_add' event_slug=ak.event.slug pk=ak.pk %}" + class="btn btn-success">{% fa5_icon 'plus' 'fas' %} {% trans "Add another slot" %}</a> + </div> + {% endif %} - {% if 'AKPlan'|check_app_installed %} - <div id='akSlotCalendar' style="margin-top: 50px;margin-bottom: 50px;"></div> - {% endif %} + {% if 'AKPlan'|check_app_installed %} + <div id='akSlotCalendar' style="margin-top: 50px;margin-bottom: 50px;"></div> + {% endif %} - <h4 style="margin-top: 30px;">{% trans "Possible Times" %}</h4> - <table class="table"> - <thead> - <tr> - <th>{% trans "Start" %}</th> - <th>{% trans "End" %}</th> - </tr> - </thead> - <tbody> - {% for a in availabilities %} + <h4 style="margin-top: 30px;">{% trans "Possible Times" %}</h4> + <table class="table"> + <thead> <tr> - <td>{{ a.start | timezone:event.timezone | date:"l H:i" }}</td> - <td>{{ a.end | timezone:event.timezone | date:"l H:i" }}</td> + <th>{% trans "Start" %}</th> + <th>{% trans "End" %}</th> </tr> - {% endfor %} - </tbody> - </table> + </thead> + <tbody> + {% for a in availabilities %} + <tr> + <td>{{ a.start | timezone:event.timezone | date:"l H:i" }}</td> + <td>{{ a.end | timezone:event.timezone | date:"l H:i" }}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% endif %} {% endblock %} diff --git a/AKSubmission/views.py b/AKSubmission/views.py index 28e6b6d1838c5244e0d801f41f1789fe2f37b28e..15d0811d467f4055394cedd0e8de0584adfa972a 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -223,10 +223,11 @@ class AKAndAKWishSubmissionView(EventSlugMixin, EventInactiveRedirectMixin, Crea tag, was_created = AKTag.objects.get_or_create(name=tag_name) self.object.tags.add(tag) - # Generate slot(s) - for duration in form.cleaned_data["durations"]: - new_slot = AKSlot(ak=self.object, duration=duration, event=self.object.event) - new_slot.save() + # Generate slot(s) (but not for wishes) + if "durations" in form.cleaned_data: + 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 @@ -269,6 +270,8 @@ class AKEditView(EventSlugMixin, EventInactiveRedirectMixin, UpdateView): return redirect(reverse_lazy('submit:submission_overview', kwargs={'event_slug': form.cleaned_data["event"].slug})) + previous_owner_count = self.object.owners.count() + super_form_valid = super().form_valid(form) # Detach existing tags @@ -279,6 +282,17 @@ class AKEditView(EventSlugMixin, EventInactiveRedirectMixin, UpdateView): tag, was_created = AKTag.objects.get_or_create(name=tag_name) self.object.tags.add(tag) + # Did this AK change from wish to AK or vice versa? + new_owner_count = self.object.owners.count() + # Now AK: + if previous_owner_count == 0 and new_owner_count > 0 and self.object.akslot_set.count() == 0: + # Create one slot with default length + AKSlot.objects.create(ak=self.object, duration=self.object.event.default_slot, event=self.object.event) + # Now wish: + elif previous_owner_count > 0 and new_owner_count == 0: + # Delete all unscheduled slots + self.object.akslot_set.filter(start__isnull=True).delete() + return super_form_valid