From d4f231767497a845ef694a05e253386be07a129b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Tue, 27 Sep 2022 23:53:16 +0200
Subject: [PATCH] Introduce GUI for slide export

This allows specifying the parameters without the need to know the GET keys
Also resolve double-compiling issue and thus switch from custom version of django-tex to the latest official release
Minor improvements to generic admin action view
This implements #152
---
 AKModel/forms.py                            |  24 ++
 AKModel/locale/de_DE/LC_MESSAGES/django.po  | 367 +++++++++++---------
 AKModel/templates/admin/AKModel/status.html |   4 +-
 AKModel/urls.py                             |   5 +-
 AKModel/views.py                            | 103 +++---
 requirements.txt                            |   2 +-
 6 files changed, 286 insertions(+), 219 deletions(-)

diff --git a/AKModel/forms.py b/AKModel/forms.py
index 1f5c07ee..28e5c678 100644
--- a/AKModel/forms.py
+++ b/AKModel/forms.py
@@ -72,3 +72,27 @@ class NewEventWizardActivateForm(forms.ModelForm):
 
 class AdminIntermediateForm(forms.Form):
     pass
+
+
+class SlideExportForm(AdminIntermediateForm):
+    num_next = forms.IntegerField(
+        min_value=0,
+        max_value=6,
+        initial=3,
+        label=_("# next AKs"),
+        help_text=_("How many next AKs should be shown on a slide?"))
+    presentation_mode = forms.TypedChoiceField(
+        initial=False,
+        label=_("Presentation only?"),
+        widget=forms.RadioSelect,
+        choices=((True, _('Yes')), (False, _('No'))),
+        coerce=lambda x: x == "True",
+        help_text=_("Restrict AKs to those that asked for chance to be presented?"))
+    wish_notes = forms.TypedChoiceField(
+        initial=False,
+        label=_("Space for notes in wishes?"),
+        widget=forms.RadioSelect,
+        choices=((True, _('Yes')), (False, _('No'))),
+        coerce=lambda x: x == "True",
+        help_text=_("Create symbols indicating space to note down owners and timeslots for wishes, e.g., to be filled "
+                    "out on a touch screen while presenting?"))
diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po
index 3aefe1d4..b9eb5368 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-09-27 14:14+0200\n"
+"POT-Creation-Date: 2022-09-27 23:49+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"
@@ -66,16 +66,16 @@ msgid "Please fill in your availabilities!"
 msgstr "Bitte Verfügbarkeiten eintragen!"
 
 #: .\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
+#: .\AKModel\models.py:124 .\AKModel\models.py:179 .\AKModel\models.py:198
+#: .\AKModel\models.py:230 .\AKModel\models.py:284 .\AKModel\models.py:350
+#: .\AKModel\models.py:383 .\AKModel\models.py:454 .\AKModel\models.py:495
 msgid "Event"
 msgstr "Event"
 
-#: .\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
+#: .\AKModel\availability\models.py:39 .\AKModel\models.py:125
+#: .\AKModel\models.py:180 .\AKModel\models.py:199 .\AKModel\models.py:231
+#: .\AKModel\models.py:285 .\AKModel\models.py:351 .\AKModel\models.py:384
+#: .\AKModel\models.py:455 .\AKModel\models.py:496
 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:358
-#: .\AKModel\models.py:377 .\AKModel\models.py:508
+#: .\AKModel\availability\models.py:56 .\AKModel\models.py:354
+#: .\AKModel\models.py:373 .\AKModel\models.py:504
 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:286
-#: .\AKModel\models.py:376 .\AKModel\models.py:453
+#: .\AKModel\availability\models.py:65 .\AKModel\models.py:290
+#: .\AKModel\models.py:372 .\AKModel\models.py:449
 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:179
-#: .\AKModel\models.py:514
+#: .\AKModel\availability\models.py:74 .\AKModel\models.py:183
+#: .\AKModel\models.py:510
 msgid "AK Category"
 msgstr "AK-Kategorie"
 
@@ -135,9 +135,46 @@ msgstr "AK-Kategorien kopieren"
 msgid "Copy ak requirements"
 msgstr "AK-Anforderungen kopieren"
 
-#: .\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
+#: .\AKModel\forms.py:82
+msgid "# next AKs"
+msgstr "# nächste AKs"
+
+#: .\AKModel\forms.py:83
+msgid "How many next AKs should be shown on a slide?"
+msgstr "Wie viele nächste AKs sollen auf einer Folie angezeigt werden?"
+
+#: .\AKModel\forms.py:86
+msgid "Presentation only?"
+msgstr "Nur Vorstellung?"
+
+#: .\AKModel\forms.py:88 .\AKModel\forms.py:95
+msgid "Yes"
+msgstr "Ja"
+
+#: .\AKModel\forms.py:88 .\AKModel\forms.py:95
+msgid "No"
+msgstr "Nein"
+
+#: .\AKModel\forms.py:90
+msgid "Restrict AKs to those that asked for chance to be presented?"
+msgstr "AKs auf solche, die um eine Vorstellung gebeten haben, einschränken?"
+
+#: .\AKModel\forms.py:93
+msgid "Space for notes in wishes?"
+msgstr "Platz für Notizen bei den Wünschen?"
+
+#: .\AKModel\forms.py:97
+msgid ""
+"Create symbols indicating space to note down owners and timeslots for "
+"wishes, e.g., to be filled out on a touch screen while presenting?"
+msgstr ""
+"Symbole anlegen, die Raum zum Notieren von Leitungen und Zeitslots "
+"fürWünsche markieren, z.B. um während der Präsentation auf einem Touchscreen "
+"ausgefüllt zu werden?"
+
+#: .\AKModel\models.py:18 .\AKModel\models.py:171 .\AKModel\models.py:195
+#: .\AKModel\models.py:214 .\AKModel\models.py:228 .\AKModel\models.py:246
+#: .\AKModel\models.py:342
 msgid "Name"
 msgstr "Name"
 
@@ -171,7 +208,7 @@ msgstr "Zeitzone"
 msgid "Time Zone where this event takes place in"
 msgstr "Zeitzone in der das Event stattfindet"
 
-#: .\AKModel\models.py:27 .\AKModel\views.py:242
+#: .\AKModel\models.py:27 .\AKModel\views.py:239
 msgid "Start"
 msgstr "Start"
 
@@ -271,71 +308,71 @@ msgstr ""
 msgid "Events"
 msgstr "Events"
 
-#: .\AKModel\models.py:115
+#: .\AKModel\models.py:119
 msgid "Nickname"
 msgstr "Spitzname"
 
-#: .\AKModel\models.py:115
+#: .\AKModel\models.py:119
 msgid "Name to identify an AK owner by"
 msgstr "Name, durch den eine AK-Leitung identifiziert wird"
 
-#: .\AKModel\models.py:116
+#: .\AKModel\models.py:120
 msgid "Slug"
 msgstr "Slug"
 
-#: .\AKModel\models.py:116
+#: .\AKModel\models.py:120
 msgid "Slug for URL generation"
 msgstr "Slug für URL-Generierung"
 
-#: .\AKModel\models.py:117
+#: .\AKModel\models.py:121
 msgid "Institution"
 msgstr "Instutution"
 
-#: .\AKModel\models.py:117
+#: .\AKModel\models.py:121
 msgid "Uni etc."
 msgstr "Universität o.ä."
 
-#: .\AKModel\models.py:118 .\AKModel\models.py:251
+#: .\AKModel\models.py:122 .\AKModel\models.py:255
 msgid "Web Link"
 msgstr "Internet Link"
 
-#: .\AKModel\models.py:118
+#: .\AKModel\models.py:122
 msgid "Link to Homepage"
 msgstr "Link zu Homepage oder Webseite"
 
-#: .\AKModel\models.py:124 .\AKModel\models.py:507
+#: .\AKModel\models.py:128 .\AKModel\models.py:503
 msgid "AK Owner"
 msgstr "AK-Leitung"
 
-#: .\AKModel\models.py:125
+#: .\AKModel\models.py:129
 msgid "AK Owners"
 msgstr "AK-Leitungen"
 
-#: .\AKModel\models.py:167
+#: .\AKModel\models.py:171
 msgid "Name of the AK Category"
 msgstr "Name der AK-Kategorie"
 
-#: .\AKModel\models.py:168 .\AKModel\models.py:192
+#: .\AKModel\models.py:172 .\AKModel\models.py:196
 msgid "Color"
 msgstr "Farbe"
 
-#: .\AKModel\models.py:168 .\AKModel\models.py:192
+#: .\AKModel\models.py:172 .\AKModel\models.py:196
 msgid "Color for displaying"
 msgstr "Farbe für die Anzeige"
 
-#: .\AKModel\models.py:169 .\AKModel\models.py:245
+#: .\AKModel\models.py:173 .\AKModel\models.py:249
 msgid "Description"
 msgstr "Beschreibung"
 
-#: .\AKModel\models.py:170
+#: .\AKModel\models.py:174
 msgid "Short description of this AK Category"
 msgstr "Beschreibung der AK-Kategorie"
 
-#: .\AKModel\models.py:171
+#: .\AKModel\models.py:175
 msgid "Present by default"
 msgstr "Defaultmäßig präsentieren"
 
-#: .\AKModel\models.py:173
+#: .\AKModel\models.py:177
 msgid ""
 "Present AKs of this category by default if AK owner did not specify whether "
 "this AK should be presented?"
@@ -343,152 +380,152 @@ msgstr ""
 "AKs dieser Kategorie standardmäßig vorstellen, wenn die Leitungen das für "
 "ihren AK nicht explizit spezifiziert haben?"
 
-#: .\AKModel\models.py:180
+#: .\AKModel\models.py:184
 msgid "AK Categories"
 msgstr "AK-Kategorien"
 
-#: .\AKModel\models.py:191
+#: .\AKModel\models.py:195
 msgid "Name of the AK Track"
 msgstr "Name des AK-Tracks"
 
-#: .\AKModel\models.py:198
+#: .\AKModel\models.py:202
 msgid "AK Track"
 msgstr "AK-Track"
 
-#: .\AKModel\models.py:199
+#: .\AKModel\models.py:203
 msgid "AK Tracks"
 msgstr "AK-Tracks"
 
-#: .\AKModel\models.py:210
+#: .\AKModel\models.py:214
 msgid "Name of the AK Tag"
 msgstr "Name das AK-Tags"
 
-#: .\AKModel\models.py:213
+#: .\AKModel\models.py:217
 msgid "AK Tag"
 msgstr "AK-Tag"
 
-#: .\AKModel\models.py:214
+#: .\AKModel\models.py:218
 msgid "AK Tags"
 msgstr "AK-Tags"
 
-#: .\AKModel\models.py:224
+#: .\AKModel\models.py:228
 msgid "Name of the Requirement"
 msgstr "Name der Anforderung"
 
-#: .\AKModel\models.py:230 .\AKModel\models.py:511
+#: .\AKModel\models.py:234 .\AKModel\models.py:507
 msgid "AK Requirement"
 msgstr "AK-Anforderung"
 
-#: .\AKModel\models.py:231
+#: .\AKModel\models.py:235
 msgid "AK Requirements"
 msgstr "AK-Anforderungen"
 
-#: .\AKModel\models.py:242
+#: .\AKModel\models.py:246
 msgid "Name of the AK"
 msgstr "Name des AKs"
 
-#: .\AKModel\models.py:243
+#: .\AKModel\models.py:247
 msgid "Short Name"
 msgstr "Kurzer Name"
 
-#: .\AKModel\models.py:244
+#: .\AKModel\models.py:248
 msgid "Name displayed in the schedule"
 msgstr "Name zur Anzeige im AK-Plan"
 
-#: .\AKModel\models.py:245
+#: .\AKModel\models.py:249
 msgid "Description of the AK"
 msgstr "Beschreibung des AKs"
 
-#: .\AKModel\models.py:247
+#: .\AKModel\models.py:251
 msgid "Owners"
 msgstr "Leitungen"
 
-#: .\AKModel\models.py:248
+#: .\AKModel\models.py:252
 msgid "Those organizing the AK"
 msgstr "Menschen, die den AK organisieren und halten"
 
-#: .\AKModel\models.py:251
+#: .\AKModel\models.py:255
 msgid "Link to wiki page"
 msgstr "Link zur Wiki Seite"
 
-#: .\AKModel\models.py:252
+#: .\AKModel\models.py:256
 msgid "Protocol Link"
 msgstr "Protokolllink"
 
-#: .\AKModel\models.py:252
+#: .\AKModel\models.py:256
 msgid "Link to protocol"
 msgstr "Link zum Protokoll"
 
-#: .\AKModel\models.py:254
+#: .\AKModel\models.py:258
 msgid "Category"
 msgstr "Kategorie"
 
-#: .\AKModel\models.py:255
+#: .\AKModel\models.py:259
 msgid "Category of the AK"
 msgstr "Kategorie des AKs"
 
-#: .\AKModel\models.py:256
+#: .\AKModel\models.py:260
 msgid "Tags"
 msgstr "Tags"
 
-#: .\AKModel\models.py:256
+#: .\AKModel\models.py:260
 msgid "Tags provided by owners"
 msgstr "Tags, die durch die AK-Leitung vergeben wurden"
 
-#: .\AKModel\models.py:257
+#: .\AKModel\models.py:261
 msgid "Track"
 msgstr "Track"
 
-#: .\AKModel\models.py:258
+#: .\AKModel\models.py:262
 msgid "Track the AK belongs to"
 msgstr "Track zu dem der AK gehört"
 
-#: .\AKModel\models.py:260
+#: .\AKModel\models.py:264
 msgid "Resolution Intention"
 msgstr "Resolutionsabsicht"
 
-#: .\AKModel\models.py:261
+#: .\AKModel\models.py:265
 msgid "Intends to submit a resolution"
 msgstr "Beabsichtigt eine Resolution einzureichen"
 
-#: .\AKModel\models.py:262
+#: .\AKModel\models.py:266
 msgid "Present this AK"
 msgstr "AK präsentieren"
 
-#: .\AKModel\models.py:263
+#: .\AKModel\models.py:267
 msgid "Present results of this AK"
 msgstr "Die Ergebnisse dieses AKs vorstellen"
 
-#: .\AKModel\models.py:265 .\AKModel\templates\admin\AKModel\status.html:97
+#: .\AKModel\models.py:269 .\AKModel\templates\admin\AKModel\status.html:95
 msgid "Requirements"
 msgstr "Anforderungen"
 
-#: .\AKModel\models.py:266
+#: .\AKModel\models.py:270
 msgid "AK's Requirements"
 msgstr "Anforderungen des AKs"
 
-#: .\AKModel\models.py:268
+#: .\AKModel\models.py:272
 msgid "Conflicting AKs"
 msgstr "AK-Konflikte"
 
-#: .\AKModel\models.py:269
+#: .\AKModel\models.py:273
 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:270
+#: .\AKModel\models.py:274
 msgid "Prerequisite AKs"
 msgstr "Vorausgesetzte AKs"
 
-#: .\AKModel\models.py:271
+#: .\AKModel\models.py:275
 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:273
+#: .\AKModel\models.py:277
 msgid "Organizational Notes"
 msgstr "Notizen zur Organisation"
 
-#: .\AKModel\models.py:274
+#: .\AKModel\models.py:278
 #, fuzzy
 #| msgid ""
 #| "Notes to organizers. These are public. For private notes, please send an "
@@ -502,258 +539,258 @@ msgstr ""
 "Anmerkungen bitte den Button für Direktnachrichten verwenden (nach dem "
 "Anlegen/Bearbeiten)."
 
-#: .\AKModel\models.py:276
+#: .\AKModel\models.py:280
 msgid "Interest"
 msgstr "Interesse"
 
-#: .\AKModel\models.py:276
+#: .\AKModel\models.py:280
 msgid "Expected number of people"
 msgstr "Erwartete Personenzahl"
 
-#: .\AKModel\models.py:277
+#: .\AKModel\models.py:281
 msgid "Interest Counter"
 msgstr "Interessenszähler"
 
-#: .\AKModel\models.py:278
+#: .\AKModel\models.py:282
 msgid "People who have indicated interest online"
 msgstr "Anzahl Personen, die online Interesse bekundet haben"
 
-#: .\AKModel\models.py:287 .\AKModel\models.py:502
+#: .\AKModel\models.py:291 .\AKModel\models.py:498
 #: .\AKModel\templates\admin\AKModel\status.html:49
-#: .\AKModel\templates\admin\AKModel\status.html:56 .\AKModel\views.py:359
+#: .\AKModel\templates\admin\AKModel\status.html:56 .\AKModel\views.py:357
 msgid "AKs"
 msgstr "AKs"
 
-#: .\AKModel\models.py:346
+#: .\AKModel\models.py:342
 msgid "Name or number of the room"
 msgstr "Name oder Nummer des Raums"
 
-#: .\AKModel\models.py:347
+#: .\AKModel\models.py:343
 msgid "Location"
 msgstr "Ort"
 
-#: .\AKModel\models.py:348
+#: .\AKModel\models.py:344
 msgid "Name or number of the location"
 msgstr "Name oder Nummer des Ortes"
 
-#: .\AKModel\models.py:349
+#: .\AKModel\models.py:345
 msgid "Capacity"
 msgstr "Kapazität"
 
-#: .\AKModel\models.py:350
+#: .\AKModel\models.py:346
 msgid "Maximum number of people (-1 for unlimited)."
 msgstr "Maximale Personenzahl (-1 wenn unbeschränkt)."
 
-#: .\AKModel\models.py:351
+#: .\AKModel\models.py:347
 msgid "Properties"
 msgstr "Eigenschaften"
 
-#: .\AKModel\models.py:352
+#: .\AKModel\models.py:348
 msgid "AK requirements fulfilled by the room"
 msgstr "AK-Anforderungen, die dieser Raum erfüllt"
 
-#: .\AKModel\models.py:359 .\AKModel\templates\admin\AKModel\status.html:33
+#: .\AKModel\models.py:355 .\AKModel\templates\admin\AKModel\status.html:33
 msgid "Rooms"
 msgstr "Räume"
 
-#: .\AKModel\models.py:376
+#: .\AKModel\models.py:372
 msgid "AK being mapped"
 msgstr "AK, der zugeordnet wird"
 
-#: .\AKModel\models.py:378
+#: .\AKModel\models.py:374
 msgid "Room the AK will take place in"
 msgstr "Raum in dem der AK stattfindet"
 
-#: .\AKModel\models.py:379
+#: .\AKModel\models.py:375
 msgid "Slot Begin"
 msgstr "Beginn des Slots"
 
-#: .\AKModel\models.py:379
+#: .\AKModel\models.py:375
 msgid "Time and date the slot begins"
 msgstr "Zeit und Datum zu der der AK beginnt"
 
-#: .\AKModel\models.py:381
+#: .\AKModel\models.py:377
 msgid "Duration"
 msgstr "Dauer"
 
-#: .\AKModel\models.py:382
+#: .\AKModel\models.py:378
 msgid "Length in hours"
 msgstr "Länge in Stunden"
 
-#: .\AKModel\models.py:384
+#: .\AKModel\models.py:380
 msgid "Scheduling fixed"
 msgstr "Planung fix"
 
-#: .\AKModel\models.py:385
+#: .\AKModel\models.py:381
 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:390
+#: .\AKModel\models.py:386
 msgid "Last update"
 msgstr "Letzte Aktualisierung"
 
-#: .\AKModel\models.py:393
+#: .\AKModel\models.py:389
 msgid "AK Slot"
 msgstr "AK-Slot"
 
-#: .\AKModel\models.py:394 .\AKModel\models.py:504
+#: .\AKModel\models.py:390 .\AKModel\models.py:500
 msgid "AK Slots"
 msgstr "AK-Slot"
 
-#: .\AKModel\models.py:416 .\AKModel\models.py:425
+#: .\AKModel\models.py:412 .\AKModel\models.py:421
 msgid "Not scheduled yet"
 msgstr "Noch nicht geplant"
 
-#: .\AKModel\models.py:454
+#: .\AKModel\models.py:450
 msgid "AK this message belongs to"
 msgstr "AK zu dem die Nachricht gehört"
 
-#: .\AKModel\models.py:455
+#: .\AKModel\models.py:451
 msgid "Message text"
 msgstr "Nachrichtentext"
 
-#: .\AKModel\models.py:456
+#: .\AKModel\models.py:452
 msgid "Message to the organizers. This is not publicly visible."
 msgstr ""
 "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar."
 
-#: .\AKModel\models.py:462
+#: .\AKModel\models.py:458
 msgid "AK Orga Message"
 msgstr "AK-Organachricht"
 
-#: .\AKModel\models.py:463
+#: .\AKModel\models.py:459
 msgid "AK Orga Messages"
 msgstr "AK-Organachrichten"
 
-#: .\AKModel\models.py:472
+#: .\AKModel\models.py:468
 msgid "Constraint Violation"
 msgstr "Constraintverletzung"
 
-#: .\AKModel\models.py:473 .\AKModel\templates\admin\AKModel\status.html:79
+#: .\AKModel\models.py:469 .\AKModel\templates\admin\AKModel\status.html:79
 msgid "Constraint Violations"
 msgstr "Constraintverletzungen"
 
-#: .\AKModel\models.py:477
+#: .\AKModel\models.py:473
 msgid "Owner has two parallel slots"
 msgstr "Leitung hat zwei Slots parallel"
 
-#: .\AKModel\models.py:478
+#: .\AKModel\models.py:474
 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:479
+#: .\AKModel\models.py:475
 msgid "Room has two AK slots scheduled at the same time"
 msgstr "Raum hat zwei AK Slots gleichzeitig"
 
-#: .\AKModel\models.py:480
+#: .\AKModel\models.py:476
 msgid "Room does not satisfy the requirement of the scheduled AK"
 msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht"
 
-#: .\AKModel\models.py:481
+#: .\AKModel\models.py:477
 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:482
+#: .\AKModel\models.py:478
 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:484
+#: .\AKModel\models.py:480
 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:485
+#: .\AKModel\models.py:481
 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:486
+#: .\AKModel\models.py:482
 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:487
+#: .\AKModel\models.py:483
 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:488
+#: .\AKModel\models.py:484
 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:491
+#: .\AKModel\models.py:487
 msgid "Warning"
 msgstr "Warnung"
 
-#: .\AKModel\models.py:492
+#: .\AKModel\models.py:488
 msgid "Violation"
 msgstr "Verletzung"
 
-#: .\AKModel\models.py:494
+#: .\AKModel\models.py:490
 msgid "Type"
 msgstr "Art"
 
-#: .\AKModel\models.py:495
+#: .\AKModel\models.py:491
 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:496
+#: .\AKModel\models.py:492
 msgid "Level"
 msgstr "Level"
 
-#: .\AKModel\models.py:497
+#: .\AKModel\models.py:493
 msgid "Severity level of the violation"
 msgstr "Schweregrad der Verletzung"
 
-#: .\AKModel\models.py:503
+#: .\AKModel\models.py:499
 msgid "AK(s) belonging to this constraint"
 msgstr "AK(s), die zu diesem Constraint gehören"
 
-#: .\AKModel\models.py:505
+#: .\AKModel\models.py:501
 msgid "AK Slot(s) belonging to this constraint"
 msgstr "AK Slot(s), die zu diesem Constraint gehören"
 
-#: .\AKModel\models.py:507
+#: .\AKModel\models.py:503
 msgid "AK Owner belonging to this constraint"
 msgstr "AK Leitung(en), die zu diesem Constraint gehören"
 
-#: .\AKModel\models.py:509
+#: .\AKModel\models.py:505
 msgid "Room belonging to this constraint"
 msgstr "Raum, der zu diesem Constraint gehört"
 
-#: .\AKModel\models.py:512
+#: .\AKModel\models.py:508
 msgid "AK Requirement belonging to this constraint"
 msgstr "AK Anforderung, die zu diesem Constraint gehört"
 
-#: .\AKModel\models.py:514
+#: .\AKModel\models.py:510
 msgid "AK Category belonging to this constraint"
 msgstr "AK Kategorie, di zu diesem Constraint gehört"
 
-#: .\AKModel\models.py:516
+#: .\AKModel\models.py:512
 msgid "Comment"
 msgstr "Kommentar"
 
-#: .\AKModel\models.py:516
+#: .\AKModel\models.py:512
 msgid "Comment or further details for this violation"
 msgstr "Kommentar oder weitere Details zu dieser Vereletzung"
 
-#: .\AKModel\models.py:519
+#: .\AKModel\models.py:515
 msgid "Timestamp"
 msgstr "Timestamp"
 
-#: .\AKModel\models.py:519
+#: .\AKModel\models.py:515
 msgid "Time of creation"
 msgstr "Zeitpunkt der ERstellung"
 
-#: .\AKModel\models.py:520
+#: .\AKModel\models.py:516
 msgid "Manually Resolved"
 msgstr "Manuell behoben"
 
-#: .\AKModel\models.py:521
+#: .\AKModel\models.py:517
 msgid "Mark this violation manually as resolved"
 msgstr "Markiere diese Verletzung manuell als behoben"
 
-#: .\AKModel\models.py:548
+#: .\AKModel\models.py:544
 #: .\AKModel\templates\admin\AKModel\requirements_overview.html:27
 msgid "Details"
 msgstr "Details"
@@ -805,7 +842,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:247
+#: .\AKModel\views.py:244
 msgid "Finish"
 msgstr "Abschluss"
 
@@ -870,7 +907,7 @@ msgid "No AKs with this requirement"
 msgstr "Kein AK mit dieser Anforderung"
 
 #: .\AKModel\templates\admin\AKModel\requirements_overview.html:45
-#: .\AKModel\templates\admin\AKModel\status.html:113
+#: .\AKModel\templates\admin\AKModel\status.html:111
 msgid "Add Requirement"
 msgstr "Anforderung hinzufügen"
 
@@ -931,27 +968,23 @@ msgstr "AKs als CSV exportieren"
 msgid "Export AKs for Wiki"
 msgstr "AKs im Wiki-Format exportieren"
 
-#: .\AKModel\templates\admin\AKModel\status.html:92
+#: .\AKModel\templates\admin\AKModel\status.html:92 .\AKModel\views.py:327
 msgid "Export AK Slides"
 msgstr "AK-Folien exportieren"
 
-#: .\AKModel\templates\admin\AKModel\status.html:94
-msgid "Export AK Slides (Presentation AKs only)"
-msgstr "AK-Folien exportieren (Nur zu präsentierende AKs)"
-
-#: .\AKModel\templates\admin\AKModel\status.html:99
+#: .\AKModel\templates\admin\AKModel\status.html:97
 msgid "No requirements yet"
 msgstr "Bisher keine Anforderungen"
 
-#: .\AKModel\templates\admin\AKModel\status.html:112
+#: .\AKModel\templates\admin\AKModel\status.html:110
 msgid "Show AKs for requirements"
 msgstr "Zu Anforderungen gehörige AKs anzeigen"
 
-#: .\AKModel\templates\admin\AKModel\status.html:116
+#: .\AKModel\templates\admin\AKModel\status.html:114
 msgid "Messages"
 msgstr "Nachrichten"
 
-#: .\AKModel\templates\admin\AKModel\status.html:118
+#: .\AKModel\templates\admin\AKModel\status.html:116
 msgid "Delete all messages"
 msgstr "Alle Nachrichten löschen"
 
@@ -988,23 +1021,23 @@ msgstr "Login"
 msgid "Register"
 msgstr "Registrieren"
 
-#: .\AKModel\views.py:144
+#: .\AKModel\views.py:145
 msgid "Event Status"
 msgstr "Eventstatus"
 
-#: .\AKModel\views.py:157
+#: .\AKModel\views.py:158
 msgid "Requirements for Event"
 msgstr "Anforderungen für das Event"
 
-#: .\AKModel\views.py:171
+#: .\AKModel\views.py:172
 msgid "AK CSV Export"
 msgstr "AK-CSV-Export"
 
-#: .\AKModel\views.py:185
+#: .\AKModel\views.py:186
 msgid "AK Wiki Export"
 msgstr "AK-Wiki-Export"
 
-#: .\AKModel\views.py:193 .\AKModel\views.py:345
+#: .\AKModel\views.py:194 .\AKModel\views.py:343
 msgid "Wishes"
 msgstr "Wünsche"
 
@@ -1012,58 +1045,66 @@ msgstr "Wünsche"
 msgid "Delete AK Orga Messages"
 msgstr "AK-Organachrichten löschen"
 
-#: .\AKModel\views.py:233
+#: .\AKModel\views.py:230
 msgid "AK Orga Messages successfully deleted"
 msgstr "AK-Organachrichten erfolgreich gelöscht"
 
-#: .\AKModel\views.py:243
+#: .\AKModel\views.py:240
 msgid "Settings"
 msgstr "Einstellungen"
 
-#: .\AKModel\views.py:244
+#: .\AKModel\views.py:241
 msgid "Event created, Prepare Import"
 msgstr "Event angelegt, Import vorbereiten"
 
-#: .\AKModel\views.py:245
+#: .\AKModel\views.py:242
 msgid "Import categories & requirements"
 msgstr "Kategorien & Anforderungen kopieren"
 
-#: .\AKModel\views.py:246
+#: .\AKModel\views.py:243
 #, fuzzy
 #| msgid "Active State"
 msgid "Activate?"
 msgstr "Aktivieren?"
 
-#: .\AKModel\views.py:305
+#: .\AKModel\views.py:302
 #, python-format
 msgid "Copied '%(obj)s'"
 msgstr "'%(obj)s' kopiert"
 
-#: .\AKModel\views.py:308
+#: .\AKModel\views.py:305
 #, python-format
 msgid "Could not copy '%(obj)s' (%(error)s)"
 msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)"
 
-#: .\AKModel\views.py:340
+#: .\AKModel\views.py:338
 msgid "Symbols"
 msgstr "Symbole"
 
-#: .\AKModel\views.py:341
+#: .\AKModel\views.py:339
 msgid "Who?"
 msgstr "Wer?"
 
-#: .\AKModel\views.py:342
+#: .\AKModel\views.py:340
 msgid "Duration(s)"
 msgstr "Dauer(n)"
 
-#: .\AKModel\views.py:343
+#: .\AKModel\views.py:341
 msgid "Reso intention?"
 msgstr "Resolutionsabsicht?"
 
-#: .\AKModel\views.py:344
+#: .\AKModel\views.py:342
 msgid "Category (for Wishes)"
 msgstr "Kategorie (für Wünsche)"
 
+#, fuzzy
+#~| msgid "Export AK Slides"
+#~ msgid "Export Slides"
+#~ msgstr "AK-Folien exportieren"
+
+#~ msgid "Export AK Slides (Presentation AKs only)"
+#~ msgstr "AK-Folien exportieren (Nur zu präsentierende AKs)"
+
 #~ msgid "Delete Orga-Messages"
 #~ msgstr "Organachrichten löschen"
 
diff --git a/AKModel/templates/admin/AKModel/status.html b/AKModel/templates/admin/AKModel/status.html
index 362c7240..19d753c9 100644
--- a/AKModel/templates/admin/AKModel/status.html
+++ b/AKModel/templates/admin/AKModel/status.html
@@ -89,9 +89,7 @@
                     <a class="btn btn-success"
                        href="{% url 'admin:ak_wiki_export' slug=event.slug %}">{% trans "Export AKs for Wiki" %}</a>
                     <a class="btn btn-success"
-                       href="{% url 'admin:ak_slide_export' event_slug=event.slug %}?num_next=3&wish_notes=False">{% trans "Export AK Slides" %}</a>
-                    <a class="btn btn-success"
-                       href="{% url 'admin:ak_slide_export' event_slug=event.slug %}?num_next=3&presentation_mode">{% trans "Export AK Slides (Presentation AKs only)" %}</a>
+                       href="{% url 'admin:ak_slide_export' event_slug=event.slug %}">{% trans "Export AK Slides" %}</a>
                 {% endif %}
 
                 <h3 class="block-header">{% trans "Requirements" %}</h3>
diff --git a/AKModel/urls.py b/AKModel/urls.py
index ca9cfe67..e86661fd 100644
--- a/AKModel/urls.py
+++ b/AKModel/urls.py
@@ -6,7 +6,7 @@ from rest_framework.routers import DefaultRouter
 from AKModel import views
 from AKModel.views import NewEventWizardStartView, NewEventWizardSettingsView, NewEventWizardPrepareImportView, \
     NewEventWizardImportView, NewEventWizardActivateView, NewEventWizardFinishView, EventStatusView, \
-    AKRequirementOverview, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, export_slides
+    AKRequirementOverview, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, ExportSlidesView
 
 api_router = DefaultRouter()
 api_router.register('akowner', views.AKOwnerViewSet, basename='AKOwner')
@@ -81,6 +81,5 @@ def get_admin_urls_event(admin_site):
              name="ak_wiki_export"),
         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"),
-
+        path('<slug:event_slug>/ak-slide-export/', ExportSlidesView.as_view(), name="ak_slide_export"),
     ]
diff --git a/AKModel/views.py b/AKModel/views.py
index 08f054f1..530a26c5 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -1,18 +1,18 @@
-from abc import ABC, abstractmethod
+import os
+import tempfile
 from itertools import zip_longest
 
 from django.contrib import admin, messages
-from django.contrib.admin.views.decorators import staff_member_required
-from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse_lazy
 from django.utils.translation import gettext_lazy as _
 from django.views.generic import TemplateView, DetailView, ListView, DeleteView, CreateView, FormView, UpdateView
-from django_tex.shortcuts import render_to_pdf
+from django_tex.core import render_template_with_context, run_tex_in_directory
+from django_tex.response import PDFResponse
 from rest_framework import viewsets, permissions, mixins
 
 from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \
-    NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm
+    NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm, SlideExportForm
 from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage, AKRequirement
 from AKModel.serializers import AKSerializer, AKSlotSerializer, RoomSerializer, AKTrackSerializer, AKCategorySerializer, \
     AKOwnerSerializer
@@ -195,13 +195,12 @@ class AKWikiExportView(AdminViewMixin, DetailView):
         return context
 
 
-class IntermediateAdminView(AdminViewMixin, FormView, ABC):
+class IntermediateAdminView(AdminViewMixin, FormView):
     template_name = "admin/AKModel/action_intermediate.html"
     form_class = AdminIntermediateForm
 
-    @abstractmethod
     def get_preview(self):
-        pass
+        return ""
 
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
@@ -217,9 +216,6 @@ class AKMessageDeleteView(EventSlugMixin, IntermediateAdminView):
     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})
 
@@ -326,41 +322,50 @@ class NewEventWizardFinishView(WizardViewMixin, DetailView):
     wizard_step = 6
 
 
-@staff_member_required
-def export_slides(request, event_slug):
-    template_name = 'admin/AKModel/export/slides.tex'
-
-    event = get_object_or_404(Event, slug=event_slug)
-
-    NEXT_AK_LIST_LENGTH = int(request.GET["num_next"]) if "num_next" in request.GET else 3
-    RESULT_PRESENTATION_MODE = True if "presentation_mode" in request.GET else False
-    SPACE_FOR_NOTES_IN_WISHES = request.GET["wish_notes"] == "True" if "wish_notes" in request.GET else False
-
-    translations = {
-        'symbols': _("Symbols"),
-        'who': _("Who?"),
-        'duration': _("Duration(s)"),
-        'reso': _("Reso intention?"),
-        'category': _("Category (for Wishes)"),
-        'wishes': _("Wishes"),
-    }
-
-    def build_ak_list_with_next_aks(ak_list):
-        next_aks_list = zip_longest(*[ak_list[i + 1:] for i in range(NEXT_AK_LIST_LENGTH)], fillvalue=None)
-        return [(ak, next_aks) for ak, next_aks in zip_longest(ak_list, next_aks_list, fillvalue=list())]
-
-    categories_with_aks, ak_wishes = event.get_categories_with_aks(wishes_seperately=True, filter=lambda
-        ak: not RESULT_PRESENTATION_MODE or (ak.present or (ak.present is None and ak.category.present_by_default)))
-
-    context = {
-        'title': event.name,
-        'categories_with_aks': [(category, build_ak_list_with_next_aks(ak_list)) for category, ak_list in
-                                categories_with_aks],
-        'subtitle': _("AKs"),
-        "wishes": build_ak_list_with_next_aks(ak_wishes),
-        "translations": translations,
-        "result_presentation_mode": RESULT_PRESENTATION_MODE,
-        "space_for_notes_in_wishes": SPACE_FOR_NOTES_IN_WISHES,
-    }
-
-    return render_to_pdf(request, template_name, context, filename='slides.pdf')
+class ExportSlidesView(EventSlugMixin, IntermediateAdminView):
+    title = _('Export AK Slides')
+    form_class = SlideExportForm
+
+    def form_valid(self, form):
+        template_name = 'admin/AKModel/export/slides.tex'
+
+        NEXT_AK_LIST_LENGTH = form.cleaned_data['num_next']
+        RESULT_PRESENTATION_MODE = form.cleaned_data["presentation_mode"]
+        SPACE_FOR_NOTES_IN_WISHES = form.cleaned_data["wish_notes"]
+
+        translations = {
+            'symbols': _("Symbols"),
+            'who': _("Who?"),
+            'duration': _("Duration(s)"),
+            'reso': _("Reso intention?"),
+            'category': _("Category (for Wishes)"),
+            'wishes': _("Wishes"),
+        }
+
+        def build_ak_list_with_next_aks(ak_list):
+            next_aks_list = zip_longest(*[ak_list[i + 1:] for i in range(NEXT_AK_LIST_LENGTH)], fillvalue=None)
+            return [(ak, next_aks) for ak, next_aks in zip_longest(ak_list, next_aks_list, fillvalue=list())]
+
+        categories_with_aks, ak_wishes = self.event.get_categories_with_aks(wishes_seperately=True, filter=lambda
+            ak: not RESULT_PRESENTATION_MODE or (ak.present or (ak.present is None and ak.category.present_by_default)))
+
+        context = {
+            'title': self.event.name,
+            'categories_with_aks': [(category, build_ak_list_with_next_aks(ak_list)) for category, ak_list in
+                                    categories_with_aks],
+            'subtitle': _("AKs"),
+            "wishes": build_ak_list_with_next_aks(ak_wishes),
+            "translations": translations,
+            "result_presentation_mode": RESULT_PRESENTATION_MODE,
+            "space_for_notes_in_wishes": SPACE_FOR_NOTES_IN_WISHES,
+        }
+
+        source = render_template_with_context(template_name, context)
+
+        # Perform real compilation (run latex twice for correct page numbers)
+        with tempfile.TemporaryDirectory() as tempdir:
+            run_tex_in_directory(source, tempdir, template_name=self.template_name)
+            os.remove(f'{tempdir}/texput.tex')
+            pdf = run_tex_in_directory(source, tempdir, template_name=self.template_name)
+
+        return PDFResponse(pdf, filename='slides.pdf')
diff --git a/requirements.txt b/requirements.txt
index 9213a6a7..e08e98f0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,7 +8,7 @@ django-simple-history==3.0.0
 django-registration-redux==2.9
 django-debug-toolbar==3.2.1
 django-bootstrap-datepicker-plus==3.0.5
-django-tex @ git+https://github.com/bhaettasch/django-tex.git@66cc6567acde4db2ac971b7707652067e664392c
+django-tex==1.1.10
 django-csp==3.7
 mysqlclient==2.0.3  # for production deployment
 pytz==2021.1
-- 
GitLab