Skip to content
Snippets Groups Projects
Commit 9b32e74f authored by Nadja Geisler's avatar Nadja Geisler :sunny:
Browse files

Merge branch 'feature-akslides' into 'main'

AK Slides

See merge request !87
parents fb3b9971 6ca2131f
No related branches found
No related tags found
1 merge request!87AK Slides
Pipeline #22516 passed
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"),
]
......
# 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
......@@ -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/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,19 +898,23 @@ msgstr "AKs als CSV exportieren"
msgid "Export AKs for Wiki"
msgstr "AKs im Wiki-Format exportieren"
#: AKModel/templates/admin/AKModel/status.html:87
#: AKModel/templates/admin/AKModel/status.html:84
msgid "Export AK Slides"
msgstr "AK-Folien exportieren"
#: 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"
......@@ -918,54 +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: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"
......
......@@ -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):
......
\documentclass[aspectratio=169]{beamer}
\usetheme[numbering=fraction, progressbar=foot]{metropolis}
\usepackage[utf8]{inputenc}
\usepackage{fontawesome5}
\title{ {{- title -}} }
\subtitle{ {{- subtitle -}} }
\date{\today}
\begin{document}
\begin{frame}
\maketitle
\end{frame}
\begin{frame}
\frametitle{ {{- translations.symbols -}} }
\faUser~ {{ translations.who }}
\faClock~ {{ translations.duration }}
\faScroll~{{ translations.reso }}
\faFilter~ {{ translations.category }}
\end{frame}
{%for category, ak_list in categories_with_aks %}
\section{ {{- category.name | latex_escape_utf8 -}} }
{% for ak, next_aks in ak_list %}
{% 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 | 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}
{% endif %}
{% endfor %}
{% endfor %}
{% if not result_presentation_mode %}
\section{ {{- translations.wishes -}} }
{% for ak, next_aks in wishes %}
%\setbeamertemplate{frame footer}{}
\begin{frame}[shrink=15]
\frametitle{ {{- ak.name | latex_escape_utf8 -}} }
\vspace{1em}
\faFilter~ {{ ak.category.name | latex_escape_utf8 }}
\faUser~
\faClock~
{{ 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}
{% endfor %}
{% endif %}
\end{document}
......@@ -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>
......
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 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 +247,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 +290,50 @@ 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 = '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
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 = 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:
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 = {
'title': event.name,
'categories_with_aks': categories_with_aks,
'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')
......@@ -52,6 +52,7 @@ INSTALLED_APPS = [
'simple_history',
'registration',
'bootstrap_datepicker_plus',
'django_tex',
]
MIDDLEWARE = [
......@@ -86,6 +87,14 @@ TEMPLATES = [
],
},
},
{
'NAME': 'tex',
'BACKEND': 'django_tex.engine.TeXEngine',
'APP_DIRS': True,
'OPTIONS': {
'environment': 'AKModel.environment.improved_tex_environment',
},
},
]
WSGI_APPLICATION = 'AKPlanning.wsgi.application'
......@@ -138,6 +147,9 @@ 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/
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment