from typing import Any, Dict, Type from django.contrib.contenttypes.models import ContentType from django.db.models import QuerySet from django.forms import BaseModelForm, modelform_factory from django.http import FileResponse, HttpRequest from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.utils.translation import gettext as _ from django.views import View from django.views.decorators.cache import never_cache from django.views.generic.detail import SingleObjectMixin from django.views.generic.list import ListView from django_tables2 import SingleTableView from guardian.shortcuts import get_objects_for_user from reversion.views import RevisionMixin from rules.contrib.views import PermissionRequiredMixin from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView from .forms import PosterGroupForm, PosterUploadForm from .models import LiveDocument, Poster, PosterGroup from .tables import LiveDocumentTable class PosterGroupListView(PermissionRequiredMixin, ListView): """Show a list of all poster groups.""" template_name = "resint/group/list.html" model = PosterGroup permission_required = "resint.view_postergroups_rule" def get_queryset(self) -> QuerySet: qs = super().get_queryset() if self.request.user.has_perm("resint.view_postergroup"): return qs return get_objects_for_user(self.request.user, "resint.view_postergroup", qs) class PosterGroupCreateView(PermissionRequiredMixin, AdvancedCreateView): """Create a new poster group.""" model = PosterGroup success_url = reverse_lazy("poster_group_list") template_name = "resint/group/create.html" success_message = _("The poster group has been saved.") form_class = PosterGroupForm permission_required = "resint.create_postergroup_rule" class PosterGroupEditView(PermissionRequiredMixin, AdvancedEditView): """Edit an existing poster group.""" model = PosterGroup success_url = reverse_lazy("poster_group_list") template_name = "resint/group/edit.html" success_message = _("The poster group has been saved.") form_class = PosterGroupForm permission_required = "resint.edit_postergroup_rule" class PosterGroupDeleteView(PermissionRequiredMixin, AdvancedDeleteView): """Delete a poster group.""" model = PosterGroup success_url = reverse_lazy("poster_group_list") success_message = _("The poster group has been deleted.") template_name = "core/pages/delete.html" permission_required = "resint.delete_postergroup_rule" class PosterListView(PermissionRequiredMixin, ListView): """Show a list of all uploaded posters.""" template_name = "resint/poster/list.html" model = Poster permission_required = "resint.view_posters_rule" def get_queryset(self) -> QuerySet: qs = Poster.objects.all().order_by("-year", "-week") if self.request.user.has_perm("resint.view_poster"): return qs allowed_groups = get_objects_for_user( self.request.user, "resint.view_poster_of_group", PosterGroup ) posters = get_objects_for_user(self.request.user, "resint.view_poster", qs) return qs.filter(group__in=allowed_groups) | posters def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: context = super().get_context_data(**kwargs) context["poster_groups"] = PosterGroup.objects.all().order_by("name") return context class RequestMixin: def get_form_kwargs(self) -> Dict[str, Any]: kwargs = super().get_form_kwargs() kwargs["request"] = self.request return kwargs class PosterUploadView(RequestMixin, PermissionRequiredMixin, AdvancedCreateView): """Upload a new poster.""" model = Poster success_url = reverse_lazy("poster_index") template_name = "resint/poster/upload.html" success_message = _("The poster has been uploaded.") form_class = PosterUploadForm permission_required = "resint.upload_poster_rule" class PosterEditView(RequestMixin, PermissionRequiredMixin, AdvancedEditView): """Edit an uploaded poster.""" model = Poster success_url = reverse_lazy("poster_index") template_name = "resint/poster/edit.html" success_message = _("The poster has been changed.") form_class = PosterUploadForm permission_required = "resint.edit_poster_rule" class PosterDeleteView(PermissionRequiredMixin, AdvancedDeleteView): """Delete an uploaded poster.""" model = Poster success_url = reverse_lazy("poster_index") success_message = _("The poster has been deleted.") template_name = "core/pages/delete.html" permission_required = "resint.delete_poster_rule" class PosterCurrentView(PermissionRequiredMixin, SingleObjectMixin, View): """Show the poster which is currently valid.""" model = PosterGroup permission_required = "resint.view_poster_pdf" def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> FileResponse: group = self.get_object() current_poster = group.current_poster file = current_poster.pdf if current_poster else group.default_pdf return FileResponse(file, content_type="application/pdf") class LiveDocumentListView(PermissionRequiredMixin, SingleTableView): """Table of all live documents.""" model = LiveDocument table_class = LiveDocumentTable permission_required = "resint.view_livedocuments_rule" template_name = "resint/live_document/list.html" def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) context["widget_types"] = [ (ContentType.objects.get_for_model(m, False), m) for m in LiveDocument.__subclasses__() ] return context @method_decorator(never_cache, name="dispatch") class LiveDocumentCreateView(PermissionRequiredMixin, AdvancedCreateView): """Create view for live documents.""" def get_model(self, request, *args, **kwargs): app_label = kwargs.get("app") model = kwargs.get("model") ct = get_object_or_404(ContentType, app_label=app_label, model=model) return ct.model_class() def get_context_data(self, **kwargs: Any) -> dict[str, Any]: context = super().get_context_data(**kwargs) context["model"] = self.model return context def get(self, request, *args, **kwargs): self.model = self.get_model(request, *args, **kwargs) return super().get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.model = self.get_model(request, *args, **kwargs) return super().post(request, *args, **kwargs) fields = "__all__" model = LiveDocument permission_required = "resint.add_livedocument_rule" template_name = "resint/live_document/create.html" success_url = reverse_lazy("live_documents") success_message = _("The live document has been created.") @method_decorator(never_cache, name="dispatch") class LiveDocumentEditView(PermissionRequiredMixin, AdvancedEditView): """Edit view for live documents.""" def get_form_class(self) -> Type[BaseModelForm]: return modelform_factory(self.object.__class__, fields=self.fields) model = LiveDocument fields = "__all__" permission_required = "resint.edit_livedocument_rule" template_name = "resint/live_document/edit.html" success_url = reverse_lazy("live_documents") success_message = _("The live document has been saved.") @method_decorator(never_cache, name="dispatch") class LiveDocumentDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView): """Delete view for live documents.""" model = LiveDocument permission_required = "resint.delete_livedocument_rule" template_name = "core/pages/delete.html" success_url = reverse_lazy("live_documents") success_message = _("The live document has been deleted.") class LiveDocumentShowView(PermissionRequiredMixin, SingleObjectMixin, View): """Show the current version of the live document.""" model = LiveDocument permission_required = "resint.view_livedocument_rule" def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> FileResponse: live_document = self.get_object() return FileResponse(live_document.get_current_file(), content_type="application/pdf")