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.http import JsonResponse 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, View from django.views.generic.detail import SingleObjectMixin from django_context_decorator import context from pretalx.common.mixins.views import EventPermissionRequired from .forms import MusicrateSettingsForm class JoinView(TemplateView): template_name = "pretalx_musicrate/join.html" def validate_token(self, token): if compare_digest( token.encode("utf-8"), self.request.event.pretalx_musicrate_settings.join_token.encode("utf-8"), ): return True messages.error(self.request, _("Invalid token")) return False def get_context_data(self, token_valid=False, **kwargs): context = super().get_context_data(**kwargs) context["token_valid"] = token_valid return context def get(self, request, *args, token, **kwargs): token_valid = self.validate_token(token) return super().get(request, *args, token_valid=token_valid, **kwargs) def post(self, request, *args, token, **kwargs): token_valid = self.validate_token(token) if token_valid: return redirect(request.path) return self.render_to_response( self.get_context_data(token_valid=token_valid, **kwargs) ) class MusicrateSettingsView(EventPermissionRequired, FormView): permission_required = "orga.change_settings" template_name = "pretalx_musicrate/settings.html" form_class = MusicrateSettingsForm def get_success_url(self): return self.request.path def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["event"] = self.request.event return kwargs def form_valid(self, form): form.save() messages.success( self.request, _("The pretalx-musicrate settings were updated.") ) return super().form_valid(form) class QRCodeView(EventPermissionRequired, TemplateView): permission_required = "orga.view_submissions" template_name = "pretalx_musicrate/qrcode.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["contents"] = self.request.build_absolute_uri( reverse( "plugins:pretalx_musicrate:join", kwargs={ "event": self.request.event.slug, "token": self.request.event.pretalx_musicrate_settings.join_token, }, ) ) 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) class MayAdvanceView(EventPermissionRequired, View): permission_required = "orga.view_submissions" def get(self, request, *args, **kwargs): return JsonResponse(True, safe=False)