From 3e4ebb72bded8f48b888b5952a5661662b59bbb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 30 Jan 2021 14:53:07 +0100
Subject: [PATCH 01/10] Add and adapt django-tex dependency

Load dependency
Use custom escaping environment
Adapt installation guidelines
---
 AKModel/environment.py | 26 ++++++++++++++++++++++++++
 AKPlanning/settings.py | 11 +++++++++++
 INSTALL.md             |  1 +
 requirements.txt       |  1 +
 4 files changed, 39 insertions(+)
 create mode 100644 AKModel/environment.py

diff --git a/AKModel/environment.py b/AKModel/environment.py
new file mode 100644
index 00000000..5883361b
--- /dev/null
+++ b/AKModel/environment.py
@@ -0,0 +1,26 @@
+# environment.py
+import re
+
+from django_tex.environment import environment
+
+# Used to filter all very special UTF-8 chars that are probably not contained in the LaTeX fonts
+# and would hence cause compilation errors
+utf8_replace_pattern = re.compile(u'[^\u0000-\u206F]', re.UNICODE)
+
+def latex_escape_utf8(value):
+    """
+    Escape latex special chars and remove invalid utf-8 values
+
+    :param value: string to escape
+    :type value: str
+    :return: escaped string
+    :rtype: str
+    """
+    return utf8_replace_pattern.sub('', value).replace('&', '\&').replace('_', '\_').replace('#', '\#').replace('$', '\$').replace('%', '\%').replace('{', '\{').replace('}', '\}')
+
+def improved_tex_environment(**options):
+    env = environment(**options)
+    env.filters.update({
+        'latex_escape_utf8': latex_escape_utf8,
+    })
+    return env
diff --git a/AKPlanning/settings.py b/AKPlanning/settings.py
index b6745ea1..f01056ac 100644
--- a/AKPlanning/settings.py
+++ b/AKPlanning/settings.py
@@ -52,6 +52,7 @@ INSTALLED_APPS = [
     'simple_history',
     'registration',
     'bootstrap_datepicker_plus',
+    'django_tex',
 ]
 
 MIDDLEWARE = [
@@ -85,6 +86,14 @@ TEMPLATES = [
             ],
         },
     },
+    {
+        'NAME': 'tex',
+        'BACKEND': 'django_tex.engine.TeXEngine',
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'environment': 'AKModel.environment.improved_tex_environment',
+        }
+    },
 ]
 
 WSGI_APPLICATION = 'AKPlanning.wsgi.application'
@@ -137,6 +146,8 @@ LANGUAGES = [
 
 INTERNAL_IPS = ['127.0.0.1', '::1']
 
+LATEX_INTERPRETER = 'pdflatex'
+
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/2.2/howto/static-files/
 
diff --git a/INSTALL.md b/INSTALL.md
index 040a5aa8..54a002e3 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -12,6 +12,7 @@ AKPlanning has two types of requirements: System requirements are dependent on o
 
 * Python 3.7 incl. development tools
 * Virtualenv
+* pdflatex & beamer class (`texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-fonts-extra`)
 * for production using uwsgi:
   * C compiler e.g. gcc
   * uwsgi
diff --git a/requirements.txt b/requirements.txt
index 176ecddc..c4d0c932 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,5 +8,6 @@ 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==1.1.8.post1
 mysqlclient==2.0.3  # for production deployment
 pytz==2021.1
-- 
GitLab


From ea3e709e7a24ce441cb29ca85184c2822df2f431 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 30 Jan 2021 14:56:09 +0100
Subject: [PATCH 02/10] Fix formation issue in simplified duration
 representation of AKSlot

Also use this representation in durations list of AK
---
 AKModel/models.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/AKModel/models.py b/AKModel/models.py
index b3719536..dcb1d457 100644
--- a/AKModel/models.py
+++ b/AKModel/models.py
@@ -264,7 +264,7 @@ class AK(models.Model):
 
     @property
     def durations_list(self):
-        return ", ".join(str(slot.duration) for slot in self.akslot_set.all())
+        return ", ".join(str(slot.duration_simplified) for slot in self.akslot_set.all())
 
     @property
     def tags_list(self):
-- 
GitLab


From 57f7794e79a7423663f34d738dbdf9d492fa31e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 30 Jan 2021 15:01:48 +0100
Subject: [PATCH 03/10] Implement simple AK to slide export

Create template for slides
Add view
Link view from status page
Update translations
---
 AKModel/admin.py                            |  7 +-
 AKModel/locale/de_DE/LC_MESSAGES/django.po  | 10 ++-
 AKModel/templates/AKModel/export/slides.tex | 72 +++++++++++++++++++++
 AKModel/templates/admin/AKModel/status.html |  2 +
 AKModel/views.py                            | 22 ++++++-
 5 files changed, 108 insertions(+), 5 deletions(-)
 create mode 100644 AKModel/templates/AKModel/export/slides.tex

diff --git a/AKModel/admin.py b/AKModel/admin.py
index 9427710f..16fe017f 100644
--- a/AKModel/admin.py
+++ b/AKModel/admin.py
@@ -1,8 +1,8 @@
+from django import forms
 from django.apps import apps
 from django.contrib import admin
 from django.contrib.admin import SimpleListFilter
 from django.db.models import Count, F
-from django import forms
 from django.shortcuts import render, redirect
 from django.urls import path, reverse_lazy
 from django.utils import timezone
@@ -16,9 +16,11 @@ from AKModel.availability.forms import AvailabilitiesFormMixin
 from AKModel.availability.models import Availability
 from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKTag, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \
     ConstraintViolation
-from AKModel.views import EventStatusView, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, AKRequirementOverview, \
+from AKModel.views import EventStatusView, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, \
+    AKRequirementOverview, \
     NewEventWizardStartView, NewEventWizardSettingsView, NewEventWizardPrepareImportView, NewEventWizardFinishView, \
     NewEventWizardImportView, NewEventWizardActivateView
+from AKModel.views import export_slides
 
 
 @admin.register(Event)
@@ -56,6 +58,7 @@ class EventAdmin(admin.ModelAdmin):
             path('<slug:event_slug>/requirements/', self.admin_site.admin_view(AKRequirementOverview.as_view()), name="event_requirement_overview"),
             path('<slug:event_slug>/ak-csv-export/', self.admin_site.admin_view(AKCSVExportView.as_view()), name="ak_csv_export"),
             path('<slug:event_slug>/ak-wiki-export/', self.admin_site.admin_view(AKWikiExportView.as_view()), name="ak_wiki_export"),
+            path('<slug:event_slug>/ak-slide-export/', export_slides, name="ak_slide_export"),
             path('<slug:slug>/delete-orga-messages/', self.admin_site.admin_view(AKMessageDeleteView.as_view()),
                  name="ak_delete_orga_messages"),
         ]
diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po
index 0f5209a9..ae977083 100644
--- a/AKModel/locale/de_DE/LC_MESSAGES/django.po
+++ b/AKModel/locale/de_DE/LC_MESSAGES/django.po
@@ -485,7 +485,7 @@ msgstr "Anzahl Personen, die online Interesse bekundet haben"
 
 #: AKModel/models.py:240 AKModel/models.py:440
 #: AKModel/templates/admin/AKModel/status.html:49
-#: AKModel/templates/admin/AKModel/status.html:56
+#: AKModel/templates/admin/AKModel/status.html:56 AKModel/views.py:194
 msgid "AKs"
 msgstr "AKs"
 
@@ -898,6 +898,10 @@ msgstr "AKs als CSV exportieren"
 msgid "Export AKs for Wiki"
 msgstr "AKs im Wiki-Format exportieren"
 
+#: AKModel/templates/admin/AKModel/status.html:82
+msgid "Export AK Slides"
+msgstr "AK-Folien exportieren"
+
 #: AKModel/templates/admin/AKModel/status.html:87
 msgid "No requirements yet"
 msgstr "Bisher keine Anforderungen"
@@ -938,6 +942,10 @@ msgstr "AK-Wiki-Export"
 msgid "AK Orga Messages successfully deleted"
 msgstr "AK-Organachrichten erfolgreich gelöscht"
 
+#: AKModel/views.py:195
+msgid "Wishes"
+msgstr "Wünsche"
+
 #: AKModel/views.py:207
 msgid "Settings"
 msgstr "Einstellungen"
diff --git a/AKModel/templates/AKModel/export/slides.tex b/AKModel/templates/AKModel/export/slides.tex
new file mode 100644
index 00000000..31f8bdcd
--- /dev/null
+++ b/AKModel/templates/AKModel/export/slides.tex
@@ -0,0 +1,72 @@
+\documentclass{beamer}
+\usetheme{metropolis}
+% \usetheme[numbering=fraction, progressbar=foot]{metropolis} TODO Activate when total number of frames bug is resolved
+
+\usepackage[utf8]{inputenc}
+\usepackage{fontawesome5}
+
+\title{ {{- title -}} }
+\subtitle{ {{- subtitle -}} }
+\date{\today}
+
+\begin{document}
+
+\begin{frame}
+\maketitle
+\end{frame}
+
+
+{%for category in categories %}
+
+    \section{ {{- category.name | latex_escape_utf8 -}} }
+
+    {% for ak in category.ak_set.all() %}
+
+        {% if not ak.wish %}
+
+            %\setbeamertemplate{frame footer}{}
+
+            \begin{frame}[shrink=15]
+                \frametitle{ {{- ak.name | latex_escape_utf8 -}} }
+
+                \vspace{1em}
+
+                \faUser~ {{ ak.owners_list | latex_escape_utf8 }}
+
+                \faClock~ {{ak.durations_list}}
+
+                {% if ak.reso %}
+                    \faScroll
+                {% endif %}
+
+                {{ ak.description | latex_escape_utf8 }}
+
+            \end{frame}
+
+        {% endif %}
+
+    {% endfor %}
+
+{% endfor %}
+
+
+\section{ {{- wish_category_title -}} }
+
+{% for ak in wishes %}
+
+    %\setbeamertemplate{frame footer}{}
+
+    \begin{frame}[shrink=15]
+        \frametitle{ {{- ak.name | latex_escape_utf8 -}} }
+
+        \vspace{1em}
+
+        \faFilter~ {{ ak.category.name | latex_escape_utf8 }}
+
+        {{ ak.description | latex_escape_utf8 }}
+
+    \end{frame}
+
+{% endfor %}
+
+\end{document}
diff --git a/AKModel/templates/admin/AKModel/status.html b/AKModel/templates/admin/AKModel/status.html
index ee84a94a..dd269c83 100644
--- a/AKModel/templates/admin/AKModel/status.html
+++ b/AKModel/templates/admin/AKModel/status.html
@@ -80,6 +80,8 @@
                        href="{% url 'admin:ak_csv_export' event_slug=event.slug %}">{% trans "Export AKs as CSV" %}</a>
                     <a class="btn btn-success"
                        href="{% url 'admin:ak_wiki_export' event_slug=event.slug %}">{% trans "Export AKs for Wiki" %}</a>
+                    <a class="btn btn-success"
+                       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/views.py b/AKModel/views.py
index cc78a0c5..aeeb7b5c 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -1,10 +1,13 @@
 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 rest_framework import viewsets, permissions, mixins
+from django_tex.shortcuts import render_to_pdf
+
 
 from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \
     NewEventWizardImportForm, NewEventWizardActivateForm
@@ -242,8 +245,6 @@ class NewEventWizardPrepareImportView(WizardViewMixin, EventSlugMixin, FormView)
     template_name = "admin/AKModel/event_wizard/created_prepare_import.html"
     wizard_step = 3
 
-
-
     def form_valid(self, form):
         # Selected a valid event to import from? Use this to go to next step of wizard
         return redirect("admin:new_event_wizard_import", event_slug=self.event.slug, import_slug=form.cleaned_data["import_event"].slug)
@@ -287,3 +288,20 @@ class NewEventWizardFinishView(WizardViewMixin, DetailView):
     model = Event
     template_name = "admin/AKModel/event_wizard/finish.html"
     wizard_step = 6
+
+
+@staff_member_required
+def export_slides(request, event_slug):
+    template_name = 'AKModel/export/slides.tex'
+
+    event = get_object_or_404(Event, slug=event_slug)
+
+    context = {
+        'title': event.name,
+        'categories': event.akcategory_set.all(),
+        'subtitle': _("AKs"),
+        'wish_category_title': _("Wishes"),
+        "wishes": [ak for ak in event.ak_set.order_by('category') if ak.wish]
+        }
+
+    return render_to_pdf(request, template_name, context, filename='slides.pdf')
-- 
GitLab


From f1e83ef38a7857a0be2d0f5d7d744fbb874c7c07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 8 May 2021 19:16:26 +0200
Subject: [PATCH 04/10] Use fork of django-tex that allows multiple consecutive
 runs of latex compile command

Additionally, this provides better escaping of user content
Set setting for consecutive runs to 2
---
 AKPlanning/settings.py | 3 ++-
 requirements.txt       | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/AKPlanning/settings.py b/AKPlanning/settings.py
index f01056ac..380475ae 100644
--- a/AKPlanning/settings.py
+++ b/AKPlanning/settings.py
@@ -92,7 +92,7 @@ TEMPLATES = [
         'APP_DIRS': True,
         'OPTIONS': {
             'environment': 'AKModel.environment.improved_tex_environment',
-        }
+        },
     },
 ]
 
@@ -147,6 +147,7 @@ LANGUAGES = [
 INTERNAL_IPS = ['127.0.0.1', '::1']
 
 LATEX_INTERPRETER = 'pdflatex'
+LATEX_RUN_COUNT = 2
 
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/2.2/howto/static-files/
diff --git a/requirements.txt b/requirements.txt
index c4d0c932..55307ddc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,6 +8,6 @@ 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==1.1.8.post1
+django-tex @ git+https://github.com/bhaettasch/django-tex.git@91db2dc814a35c6e1d4a4b758a1a7b56822305b5
 mysqlclient==2.0.3  # for production deployment
 pytz==2021.1
-- 
GitLab


From c3ddea6001e7237c9ae998258f545bc5854fe787 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 8 May 2021 20:02:05 +0200
Subject: [PATCH 05/10] Show number of overall slides on export slides

---
 AKModel/templates/AKModel/export/slides.tex | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/AKModel/templates/AKModel/export/slides.tex b/AKModel/templates/AKModel/export/slides.tex
index 31f8bdcd..4e2508af 100644
--- a/AKModel/templates/AKModel/export/slides.tex
+++ b/AKModel/templates/AKModel/export/slides.tex
@@ -1,6 +1,5 @@
 \documentclass{beamer}
-\usetheme{metropolis}
-% \usetheme[numbering=fraction, progressbar=foot]{metropolis} TODO Activate when total number of frames bug is resolved
+\usetheme[numbering=fraction, progressbar=foot]{metropolis}
 
 \usepackage[utf8]{inputenc}
 \usepackage{fontawesome5}
@@ -39,7 +38,7 @@
                     \faScroll
                 {% endif %}
 
-                {{ ak.description | latex_escape_utf8 }}
+                {{ ak.description | truncatechars(500) | latex_escape_utf8 }}
 
             \end{frame}
 
-- 
GitLab


From ee8617e0771d04e6ffb8598e321a8e70d80ae9b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sat, 8 May 2021 20:02:40 +0200
Subject: [PATCH 06/10] Truncate length of description texts for AK info slides

---
 AKModel/templates/AKModel/export/slides.tex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/AKModel/templates/AKModel/export/slides.tex b/AKModel/templates/AKModel/export/slides.tex
index 4e2508af..4bf131d6 100644
--- a/AKModel/templates/AKModel/export/slides.tex
+++ b/AKModel/templates/AKModel/export/slides.tex
@@ -62,7 +62,7 @@
 
         \faFilter~ {{ ak.category.name | latex_escape_utf8 }}
 
-        {{ ak.description | latex_escape_utf8 }}
+        {{ ak.description | truncatechars(500) | latex_escape_utf8 }}
 
     \end{frame}
 
-- 
GitLab


From efe34bd3fe2bd1701426254d2fa802d2c4efddc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 9 May 2021 00:12:47 +0200
Subject: [PATCH 07/10] Show symbol legend and placeholder symbols for wishes
 in slides

Additionally, change slide ratio to 16:9
---
 AKModel/locale/de_DE/LC_MESSAGES/django.po  | 84 +++++++++++++--------
 AKModel/templates/AKModel/export/slides.tex | 21 +++++-
 AKModel/views.py                            | 13 +++-
 3 files changed, 82 insertions(+), 36 deletions(-)

diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po
index ae977083..22e42f30 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: 2021-04-29 22:48+0000\n"
+"POT-Creation-Date: 2021-05-08 18:07+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -11,7 +11,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: AKModel/admin.py:66 AKModel/admin.py:67
+#: AKModel/admin.py:69 AKModel/admin.py:70
 #: AKModel/templates/admin/AKModel/event_wizard/activate.html:32
 #: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:48
 #: AKModel/templates/admin/AKModel/event_wizard/finish.html:21
@@ -21,23 +21,23 @@ msgstr ""
 msgid "Status"
 msgstr "Status"
 
-#: AKModel/admin.py:153
+#: AKModel/admin.py:156
 msgid "Wish"
 msgstr "AK-Wunsch"
 
-#: AKModel/admin.py:159
+#: AKModel/admin.py:162
 msgid "Is wish"
 msgstr "Ist ein Wunsch"
 
-#: AKModel/admin.py:160
+#: AKModel/admin.py:163
 msgid "Is not a wish"
 msgstr "Ist kein Wunsch"
 
-#: AKModel/admin.py:187
+#: AKModel/admin.py:209
 msgid "Export to wiki syntax"
 msgstr "In Wiki-Syntax exportieren"
 
-#: AKModel/admin.py:283
+#: AKModel/admin.py:317
 msgid "AK Details"
 msgstr "AK-Details"
 
@@ -170,7 +170,7 @@ msgstr "Zeitzone"
 msgid "Time Zone where this event takes place in"
 msgstr "Zeitzone in der das Event stattfindet"
 
-#: AKModel/models.py:25 AKModel/views.py:206
+#: AKModel/models.py:25 AKModel/views.py:209
 msgid "Start"
 msgstr "Start"
 
@@ -430,7 +430,7 @@ msgstr "AK präsentieren"
 msgid "Present results of this AK"
 msgstr "Die Ergebnisse dieses AKs vorstellen"
 
-#: AKModel/models.py:218 AKModel/templates/admin/AKModel/status.html:85
+#: AKModel/models.py:218 AKModel/templates/admin/AKModel/status.html:87
 msgid "Requirements"
 msgstr "Anforderungen"
 
@@ -485,7 +485,7 @@ msgstr "Anzahl Personen, die online Interesse bekundet haben"
 
 #: AKModel/models.py:240 AKModel/models.py:440
 #: AKModel/templates/admin/AKModel/status.html:49
-#: AKModel/templates/admin/AKModel/status.html:56 AKModel/views.py:194
+#: AKModel/templates/admin/AKModel/status.html:56 AKModel/views.py:310
 msgid "AKs"
 msgstr "AKs"
 
@@ -761,7 +761,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:211
+#: AKModel/views.py:214
 msgid "Finish"
 msgstr "Abschluss"
 
@@ -845,7 +845,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:101
+#: AKModel/templates/admin/AKModel/status.html:103
 msgid "Add Requirement"
 msgstr "Anforderung hinzufügen"
 
@@ -898,23 +898,23 @@ msgstr "AKs als CSV exportieren"
 msgid "Export AKs for Wiki"
 msgstr "AKs im Wiki-Format exportieren"
 
-#: AKModel/templates/admin/AKModel/status.html:82
+#: AKModel/templates/admin/AKModel/status.html:84
 msgid "Export AK Slides"
 msgstr "AK-Folien exportieren"
 
-#: AKModel/templates/admin/AKModel/status.html:87
+#: AKModel/templates/admin/AKModel/status.html:89
 msgid "No requirements yet"
 msgstr "Bisher keine Anforderungen"
 
-#: AKModel/templates/admin/AKModel/status.html:100
+#: AKModel/templates/admin/AKModel/status.html:102
 msgid "Show AKs for requirements"
 msgstr "Zu Anforderungen gehörige AKs anzeigen"
 
-#: AKModel/templates/admin/AKModel/status.html:104
+#: AKModel/templates/admin/AKModel/status.html:106
 msgid "Messages"
 msgstr "Nachrichten"
 
-#: AKModel/templates/admin/AKModel/status.html:106
+#: AKModel/templates/admin/AKModel/status.html:108
 msgid "Delete all messages"
 msgstr "Alle Nachrichten löschen"
 
@@ -922,58 +922,78 @@ msgstr "Alle Nachrichten löschen"
 msgid "Active Events"
 msgstr "Aktive Events"
 
-#: AKModel/views.py:136
+#: AKModel/views.py:139
 msgid "Event Status"
 msgstr "Eventstatus"
 
-#: AKModel/views.py:149
+#: AKModel/views.py:152
 msgid "Requirements for Event"
 msgstr "Anforderungen für das Event"
 
-#: AKModel/views.py:163
+#: AKModel/views.py:166
 msgid "AK CSV Export"
 msgstr "AK-CSV-Export"
 
-#: AKModel/views.py:177
+#: AKModel/views.py:180
 msgid "AK Wiki Export"
 msgstr "AK-Wiki-Export"
 
-#: AKModel/views.py:197
+#: AKModel/views.py:200
 msgid "AK Orga Messages successfully deleted"
 msgstr "AK-Organachrichten erfolgreich gelöscht"
 
-#: AKModel/views.py:195
-msgid "Wishes"
-msgstr "Wünsche"
-
-#: AKModel/views.py:207
+#: AKModel/views.py:210
 msgid "Settings"
 msgstr "Einstellungen"
 
-#: AKModel/views.py:208
+#: AKModel/views.py:211
 msgid "Event created, Prepare Import"
 msgstr "Event angelegt, Import vorbereiten"
 
-#: AKModel/views.py:209
+#: AKModel/views.py:212
 msgid "Import categories & requirements"
 msgstr "Kategorien & Anforderungen kopieren"
 
-#: AKModel/views.py:210
+#: AKModel/views.py:213
 #, fuzzy
 #| msgid "Active State"
 msgid "Activate?"
 msgstr "Aktivieren?"
 
-#: AKModel/views.py:270
+#: AKModel/views.py:271
 #, python-format
 msgid "Copied '%(obj)s'"
 msgstr "'%(obj)s' kopiert"
 
-#: AKModel/views.py:272
+#: AKModel/views.py:273
 #, python-format
 msgid "Could not copy '%(obj)s' (%(error)s)"
 msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)"
 
+#: AKModel/views.py:300
+msgid "Symbols"
+msgstr "Symbole"
+
+#: AKModel/views.py:301
+msgid "Who?"
+msgstr "Wer?"
+
+#: AKModel/views.py:302
+msgid "Duration(s)"
+msgstr "Dauer(n)"
+
+#: AKModel/views.py:303
+msgid "Reso intention?"
+msgstr "Resolutionsabsicht?"
+
+#: AKModel/views.py:304
+msgid "Category (for Wishes)"
+msgstr "Kategorie (für Wünsche)"
+
+#: AKModel/views.py:311
+msgid "Wishes"
+msgstr "Wünsche"
+
 #~ msgid "Confirm"
 #~ msgstr "Bestätigen"
 
diff --git a/AKModel/templates/AKModel/export/slides.tex b/AKModel/templates/AKModel/export/slides.tex
index 4bf131d6..d7c9ce62 100644
--- a/AKModel/templates/AKModel/export/slides.tex
+++ b/AKModel/templates/AKModel/export/slides.tex
@@ -1,4 +1,4 @@
-\documentclass{beamer}
+\documentclass[aspectratio=169]{beamer}
 \usetheme[numbering=fraction, progressbar=foot]{metropolis}
 
 \usepackage[utf8]{inputenc}
@@ -14,6 +14,19 @@
 \maketitle
 \end{frame}
 
+\begin{frame}
+    \frametitle{ {{- translations.symbols -}} }
+
+    \faUser~ {{ translations.who }}
+
+    \faClock~ {{ translations.duration }}
+
+    \faScroll~{{ translations.reso }}
+
+    \faFilter~ {{ translations.category }}
+
+\end{frame}
+
 
 {%for category in categories %}
 
@@ -49,7 +62,7 @@
 {% endfor %}
 
 
-\section{ {{- wish_category_title -}} }
+\section{ {{- translations.wishes -}} }
 
 {% for ak in wishes %}
 
@@ -62,6 +75,10 @@
 
         \faFilter~ {{ ak.category.name | latex_escape_utf8 }}
 
+        \faUser~
+
+        \faClock~
+
         {{ ak.description | truncatechars(500) | latex_escape_utf8 }}
 
     \end{frame}
diff --git a/AKModel/views.py b/AKModel/views.py
index aeeb7b5c..ea7e09a2 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -296,12 +296,21 @@ def export_slides(request, event_slug):
 
     event = get_object_or_404(Event, slug=event_slug)
 
+    translations = {
+        'symbols': _("Symbols"),
+        'who': _("Who?"),
+        'duration': _("Duration(s)"),
+        'reso': _("Reso intention?"),
+        'category': _("Category (for Wishes)"),
+        'wishes': _("Wishes"),
+    }
+
     context = {
         'title': event.name,
         'categories': event.akcategory_set.all(),
         'subtitle': _("AKs"),
-        'wish_category_title': _("Wishes"),
-        "wishes": [ak for ak in event.ak_set.order_by('category') if ak.wish]
+        "wishes": [ak for ak in event.ak_set.order_by('category') if ak.wish],
+        "translations": translations,
         }
 
     return render_to_pdf(request, template_name, context, filename='slides.pdf')
-- 
GitLab


From 8fa36c56d58c51247b1eef3bf9e1390f6d24e45b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 9 May 2021 00:24:09 +0200
Subject: [PATCH 08/10] Move slides template to semantically correct place

---
 AKModel/templates/{ => admin}/AKModel/export/slides.tex | 0
 AKModel/views.py                                        | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename AKModel/templates/{ => admin}/AKModel/export/slides.tex (100%)

diff --git a/AKModel/templates/AKModel/export/slides.tex b/AKModel/templates/admin/AKModel/export/slides.tex
similarity index 100%
rename from AKModel/templates/AKModel/export/slides.tex
rename to AKModel/templates/admin/AKModel/export/slides.tex
diff --git a/AKModel/views.py b/AKModel/views.py
index ea7e09a2..b620f1e7 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -292,7 +292,7 @@ class NewEventWizardFinishView(WizardViewMixin, DetailView):
 
 @staff_member_required
 def export_slides(request, event_slug):
-    template_name = 'AKModel/export/slides.tex'
+    template_name = 'admin/AKModel/export/slides.tex'
 
     event = get_object_or_404(Event, slug=event_slug)
 
-- 
GitLab


From 58301524ca3454f360063e33394319a169fc9b77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 9 May 2021 01:34:41 +0200
Subject: [PATCH 09/10] Display list of next AKs on slides

---
 .../templates/admin/AKModel/export/slides.tex | 26 +++++++++++++++----
 AKModel/views.py                              | 24 +++++++++++++++--
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/AKModel/templates/admin/AKModel/export/slides.tex b/AKModel/templates/admin/AKModel/export/slides.tex
index d7c9ce62..814c57ed 100644
--- a/AKModel/templates/admin/AKModel/export/slides.tex
+++ b/AKModel/templates/admin/AKModel/export/slides.tex
@@ -28,11 +28,11 @@
 \end{frame}
 
 
-{%for category in categories %}
+{%for category, ak_list in categories_with_aks %}
 
     \section{ {{- category.name | latex_escape_utf8 -}} }
 
-    {% for ak in category.ak_set.all() %}
+    {% for ak, next_aks in ak_list %}
 
         {% if not ak.wish %}
 
@@ -51,7 +51,15 @@
                     \faScroll
                 {% endif %}
 
-                {{ ak.description | truncatechars(500) | latex_escape_utf8 }}
+                {{ ak.description | truncatechars(400) | latex_escape_utf8 }}
+
+                \vspace{2em}
+
+                \begin{scriptsize}
+                    {% for n_ak in next_aks %}
+                        {% if n_ak %}\hfill \faAngleDoubleRight~ {{- n_ak.name | latex_escape_utf8 -}}{% endif %}
+                    {% endfor %}
+                \end{scriptsize}
 
             \end{frame}
 
@@ -64,7 +72,7 @@
 
 \section{ {{- translations.wishes -}} }
 
-{% for ak in wishes %}
+{% for ak, next_aks in wishes %}
 
     %\setbeamertemplate{frame footer}{}
 
@@ -79,7 +87,15 @@
 
         \faClock~
 
-        {{ ak.description | truncatechars(500) | latex_escape_utf8 }}
+        {{ ak.description | truncatechars(400) | latex_escape_utf8 }}
+
+        \vspace{2em}
+
+        \begin{scriptsize}
+            {% for n_ak in next_aks %}
+                {% if n_ak %}\hfill \faAngleDoubleRight~ {{- n_ak.name | latex_escape_utf8 -}}{% endif %}
+            {% endfor %}
+        \end{scriptsize}
 
     \end{frame}
 
diff --git a/AKModel/views.py b/AKModel/views.py
index b620f1e7..06bd3211 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -1,3 +1,5 @@
+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
@@ -296,6 +298,8 @@ def export_slides(request, event_slug):
 
     event = get_object_or_404(Event, slug=event_slug)
 
+    NEXT_AK_LIST_LENGTH = 4
+
     translations = {
         'symbols': _("Symbols"),
         'who': _("Who?"),
@@ -305,11 +309,27 @@ def export_slides(request, event_slug):
         '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 = event.akcategory_set.all()
+    categories_with_aks = []
+    ak_wishes = []
+    for category in categories:
+        ak_list = []
+        for ak in category.ak_set.all(): # order_by("owners").distinct():
+            if ak.wish:
+                ak_wishes.append(ak)
+            else:
+                ak_list.append(ak)
+        categories_with_aks.append((category, build_ak_list_with_next_aks(ak_list)))
+
     context = {
         'title': event.name,
-        'categories': event.akcategory_set.all(),
+        'categories_with_aks': categories_with_aks,
         'subtitle': _("AKs"),
-        "wishes": [ak for ak in event.ak_set.order_by('category') if ak.wish],
+        "wishes": build_ak_list_with_next_aks(ak_wishes),
         "translations": translations,
         }
 
-- 
GitLab


From f469c2b28c4aedbf5d0e2278231cec4da119bea1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 9 May 2021 01:46:01 +0200
Subject: [PATCH 10/10] Introduce result presentation mode for slides and allow
 to specify mode and num of next AKs via GET params

The export now allows to optional params, ?presentation_mode (without args) and ?num_next=<int> (default 3)
---
 .../templates/admin/AKModel/export/slides.tex | 39 ++++++++++---------
 AKModel/views.py                              |  7 +++-
 2 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/AKModel/templates/admin/AKModel/export/slides.tex b/AKModel/templates/admin/AKModel/export/slides.tex
index 814c57ed..d30f70e5 100644
--- a/AKModel/templates/admin/AKModel/export/slides.tex
+++ b/AKModel/templates/admin/AKModel/export/slides.tex
@@ -69,36 +69,37 @@
 
 {% endfor %}
 
+{% if not result_presentation_mode %}
 
-\section{ {{- translations.wishes -}} }
+    \section{ {{- translations.wishes -}} }
 
-{% for ak, next_aks in wishes %}
+    {% for ak, next_aks in wishes %}
 
-    %\setbeamertemplate{frame footer}{}
+        %\setbeamertemplate{frame footer}{}
 
-    \begin{frame}[shrink=15]
-        \frametitle{ {{- ak.name | latex_escape_utf8 -}} }
+        \begin{frame}[shrink=15]
+            \frametitle{ {{- ak.name | latex_escape_utf8 -}} }
 
-        \vspace{1em}
+            \vspace{1em}
 
-        \faFilter~ {{ ak.category.name | latex_escape_utf8 }}
+            \faFilter~ {{ ak.category.name | latex_escape_utf8 }}
 
-        \faUser~
+            \faUser~
 
-        \faClock~
+            \faClock~
 
-        {{ ak.description | truncatechars(400) | latex_escape_utf8 }}
+            {{ ak.description | truncatechars(400) | latex_escape_utf8 }}
 
-        \vspace{2em}
+            \vspace{2em}
 
-        \begin{scriptsize}
-            {% for n_ak in next_aks %}
-                {% if n_ak %}\hfill \faAngleDoubleRight~ {{- n_ak.name | latex_escape_utf8 -}}{% endif %}
-            {% endfor %}
-        \end{scriptsize}
+            \begin{scriptsize}
+                {% for n_ak in next_aks %}
+                    {% if n_ak %}\hfill \faAngleDoubleRight~ {{- n_ak.name | latex_escape_utf8 -}}{% endif %}
+                {% endfor %}
+            \end{scriptsize}
 
-    \end{frame}
-
-{% endfor %}
+        \end{frame}
+    {% endfor %}
+{% endif %}
 
 \end{document}
diff --git a/AKModel/views.py b/AKModel/views.py
index 06bd3211..c1926d7d 100644
--- a/AKModel/views.py
+++ b/AKModel/views.py
@@ -298,7 +298,8 @@ def export_slides(request, event_slug):
 
     event = get_object_or_404(Event, slug=event_slug)
 
-    NEXT_AK_LIST_LENGTH = 4
+    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
 
     translations = {
         'symbols': _("Symbols"),
@@ -322,7 +323,8 @@ def export_slides(request, event_slug):
             if ak.wish:
                 ak_wishes.append(ak)
             else:
-                ak_list.append(ak)
+                if not RESULT_PRESENTATION_MODE or ak.present:
+                    ak_list.append(ak)
         categories_with_aks.append((category, build_ak_list_with_next_aks(ak_list)))
 
     context = {
@@ -331,6 +333,7 @@ def export_slides(request, event_slug):
         'subtitle': _("AKs"),
         "wishes": build_ak_list_with_next_aks(ak_wishes),
         "translations": translations,
+        "result_presentation_mode": RESULT_PRESENTATION_MODE,
         }
 
     return render_to_pdf(request, template_name, context, filename='slides.pdf')
-- 
GitLab