kadenios/elections/mixins.py

126 lines
4 KiB
Python

from typing import Any
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Q, QuerySet
from django.http.request import HttpRequest
from django.urls import reverse
from django.utils import timezone
from django.views.generic.detail import SingleObjectMixin
from elections.typing import AuthenticatedRequest
from .models import Election, Option, Question
class AdminOnlyMixin(PermissionRequiredMixin):
"""Restreint l'accès aux admins"""
request: AuthenticatedRequest
permission_required = "elections.election_admin"
class SelectElectionMixin:
"""Sélectionne automatiquement les foreignkeys voulues"""
model: type
def get_queryset(self) -> QuerySet:
qs = super().get_queryset() # pyright: ignore
if self.model is Question:
return qs.select_related("election")
elif self.model is Option:
return qs.select_related("question__election")
return qs
class RestrictAccessMixin(SelectElectionMixin):
"""Permet de restreindre l'accès à des élections/questions/options"""
f_prefixes = {
Election: "",
Question: "election__",
Option: "question__election__",
}
def get_f_prefix(self) -> str:
return self.f_prefixes.get(self.model, "")
def get_filters(self) -> dict[str, Any]:
return {}
def get_queryset(self) -> QuerySet:
qs = super().get_queryset()
if self.model in self.f_prefixes:
return qs.filter(**self.get_filters())
# On ne sait pas ce qu'on manipule donc on ne renvoie rien
return qs.none()
class OpenElectionOnlyMixin(RestrictAccessMixin):
"""N'autorise la vue que lorsque l'élection est ouverte"""
def get_filters(self) -> dict[str, Any]:
f_prefix = self.get_f_prefix()
# On ne peut modifier que les élections qui n'ont pas commencé, et
# accessoirement qui ne sont pas dépouillées ou archivées
# TODO: décider si on choisit pas de juste garder les dates d'ouverture
filters = super().get_filters()
filters[f_prefix + "start_date__lt"] = timezone.now()
filters[f_prefix + "end_date__gt"] = timezone.now()
filters[f_prefix + "visible"] = True
filters[f_prefix + "tallied"] = False
filters[f_prefix + "archived"] = False
return filters
class CreatorOnlyMixin(AdminOnlyMixin, RestrictAccessMixin, SingleObjectMixin):
"""Restreint l'accès au créateurice de l'élection"""
def get_next_url(self):
return reverse("kadenios")
def get_filters(self) -> dict[str, Any]:
filters = super().get_filters()
# TODO: change the way we collect the user according to the model used
filters[self.get_f_prefix() + "created_by"] = self.request.user
return filters
class CreatorOnlyEditMixin(CreatorOnlyMixin):
"""Permet au créateurice de modifier l'élection implicitement"""
def get_filters(self) -> dict[str, Any]:
# On ne peut modifier que les élections qui n'ont pas commencé
filters = super().get_filters()
filters[self.get_f_prefix() + "start_date__gt"] = timezone.now()
return filters
class ClosedElectionMixin(CreatorOnlyMixin):
"""Permet d'agir sur une élection terminée"""
def get_filters(self) -> dict[str, Any]:
f_prefix = self.get_f_prefix()
# L'élection doit être terminée et non archivée
filters = super().get_filters()
filters[f_prefix + "end_date__lt"] = timezone.now()
filters[f_prefix + "archived"] = False
return filters
class NotArchivedMixin:
"""
Permet de ne garder que les élections non archivées, et visibles
ou dont on est l'admin
"""
request: HttpRequest
def get_queryset(self) -> QuerySet:
user = self.request.user
qs = super().get_queryset() # pyright: ignore
if user.is_authenticated:
return qs.filter(Q(archived=False, visible=True) | Q(created_by=user))
return qs.filter(archived=False, visible=True)