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 kif/akplanning!87
parents fb3b9971 6ca2131f
No related branches found
No related tags found
No related merge requests found
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.
Finish editing this message first!
Please register or to comment