From e070fd128145263d96300e99b929d4eebe1919b5 Mon Sep 17 00:00:00 2001 From: Luca Date: Fri, 15 Dec 2023 17:12:12 +0100 Subject: [PATCH] feat: add presenter view --- .../templates/pretalx_musicrate/present.html | 4 + .../pretalx_musicrate/submission_base.html | 55 +++++++++ pretalx_musicrate/urls.py | 3 +- pretalx_musicrate/views.py | 112 ++++++++++++++++++ pyproject.toml | 1 + 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 pretalx_musicrate/templates/pretalx_musicrate/present.html create mode 100644 pretalx_musicrate/templates/pretalx_musicrate/submission_base.html diff --git a/pretalx_musicrate/templates/pretalx_musicrate/present.html b/pretalx_musicrate/templates/pretalx_musicrate/present.html new file mode 100644 index 0000000..4a1870e --- /dev/null +++ b/pretalx_musicrate/templates/pretalx_musicrate/present.html @@ -0,0 +1,4 @@ +{% extends "pretalx_musicrate/submission_base.html" %} + +{% block submission_content %} +{% endblock %} diff --git a/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html b/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html new file mode 100644 index 0000000..4be5863 --- /dev/null +++ b/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html @@ -0,0 +1,55 @@ +{% extends "cfp/event/base.html" %} +{% load compress %} +{% load i18n %} + +{% block title %}{{ submission.title }} ::{% endblock %} + +{% block cfp_header %} + {% compress css %} + + {% endcompress %} + {% block submission_header %} + {% endblock %} +{% endblock %} + +{% block content %} + {% translate "(not specified)" as not_specified %} +

{{ submission.title }}

+

+ {{ genre|default:not_specified }} · {{ origin|default:not_specified }} + {% if submission.internal_notes %} +
+ {{ submission.internal_notes }} + {% endif %} +

+ {% block submission_content %} + {% endblock %} +
+ {% if prev %} + < {% translate "Previous" %} + {% else %} + + {% endif %} + {% if index and count %} + {{ index }}/{{ count }} + {% endif %} + {% if next and can_continue %} + {% translate "Next" %} > + {% else %} + + {% endif %} +
+{% endblock %} diff --git a/pretalx_musicrate/urls.py b/pretalx_musicrate/urls.py index e638c96..b2f86cc 100644 --- a/pretalx_musicrate/urls.py +++ b/pretalx_musicrate/urls.py @@ -1,6 +1,6 @@ from django.urls import include, path -from .views import JoinView, MusicrateSettingsView, QRCodeView +from .views import JoinView, MusicrateSettingsView, PresenterView, QRCodeView urlpatterns = [ path( @@ -13,6 +13,7 @@ urlpatterns = [ include( [ path("", QRCodeView.as_view(), name="qrcode"), + path("present//", PresenterView.as_view(), name="present"), path("/", JoinView.as_view(), name="join"), ] ), diff --git a/pretalx_musicrate/views.py b/pretalx_musicrate/views.py index 8970527..5e73616 100644 --- a/pretalx_musicrate/views.py +++ b/pretalx_musicrate/views.py @@ -1,10 +1,16 @@ from hmac import compare_digest +from operator import itemgetter from django.contrib import messages +from django.db.models import F, Max, Min, Window +from django.db.models.functions import RowNumber from django.shortcuts import redirect from django.urls import reverse +from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView, TemplateView +from django.views.generic.detail import SingleObjectMixin +from django_context_decorator import context from pretalx.common.mixins.views import EventPermissionRequired from .forms import MusicrateSettingsForm @@ -77,3 +83,109 @@ class QRCodeView(EventPermissionRequired, TemplateView): ) ) return context + + +class SubmissionMixin(SingleObjectMixin): + slug_field = "code" + slug_url_kwarg = "code" + + def get_queryset(self): + return self.request.event.submissions.prefetch_related("answers").filter( + submission_type__in=self.request.event.pretalx_musicrate_settings.submission_types.all() + ) + + @context + @cached_property + def submission(self): + return self.get_object() + + @context + @cached_property + def genre(self): + return ( + self.submission.answers.filter( + question=self.request.event.pretalx_musicrate_settings.genre_question + ) + .values_list("answer", flat=True) + .first() + ) + + @context + @cached_property + def origin(self): + return ( + self.submission.answers.filter( + question=self.request.event.pretalx_musicrate_settings.origin_question + ) + .values_list("answer", flat=True) + .first() + ) + + def get_url_kwargs(self, **kwargs): + return self.request.resolver_match.kwargs | kwargs + + @context + @cached_property + def prev(self): + prev = ( + self.get_queryset() + .annotate(prev=Max("created")) + .filter(created__lt=self.submission.created, created=F("prev")) + .first() + ) + if prev is None: + return None + return reverse( + self.request.resolver_match.view_name, + kwargs=self.get_url_kwargs(code=prev.code), + ) + + @context + @cached_property + def index(self): + return next( + map( + itemgetter(1), + filter( + lambda s: s[0] == self.submission.pk, + self.get_queryset() + .annotate(index=Window(expression=RowNumber(), order_by="created")) + .values_list("pk", "index"), + ), + ) + ) + + @context + @cached_property + def count(self): + return self.get_queryset().count() + + @context + @cached_property + def next(self): + next = ( + self.get_queryset() + .annotate(next=Min("created")) + .filter(created__gt=self.submission.created, created=F("next")) + .first() + ) + if next is None: + return None + return reverse( + self.request.resolver_match.view_name, + kwargs=self.get_url_kwargs(code=next.code), + ) + + +class PresenterView(EventPermissionRequired, SubmissionMixin, TemplateView): + permission_required = "orga.view_submissions" + template_name = "pretalx_musicrate/present.html" + + @context + @property + def can_continue(self): + return True + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return super().get(request, *args, **kwargs) diff --git a/pyproject.toml b/pyproject.toml index 8294e67..bf22e53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ maintainers = [ dependencies = [ "Django", + "django-context-decorator", "django-i18nfield", "pretalx", "qrcode",