174 lines
5.9 KiB
Python
174 lines
5.9 KiB
Python
from django.contrib import messages
|
|
from django.contrib.messages.views import SuccessMessageMixin
|
|
from django.db.models import Count, Prefetch
|
|
from django.http import HttpResponseRedirect
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
from django.utils.text import slugify
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import CreateView, DetailView, RedirectView, UpdateView
|
|
from django.views.generic.detail import SingleObjectMixin
|
|
|
|
from .forms import OptionFormSet
|
|
from .models import Election, Option, Question
|
|
|
|
# TODO: access control *everywhere*
|
|
|
|
|
|
class ElectionCreateView(SuccessMessageMixin, CreateView):
|
|
model = Election
|
|
fields = ["name", "description", "start_date", "end_date"]
|
|
template_name = "elections/election_create.html"
|
|
success_message = _("Élection crée avec succès !")
|
|
|
|
def get_success_url(self):
|
|
return reverse("election.admin", args=[self.object.pk])
|
|
|
|
def form_valid(self, form):
|
|
# We need to add the short name and the creator od the election
|
|
form.instance.short_name = slugify(
|
|
str(form.instance.start_date.year) + "_" + form.instance.name
|
|
)[:50]
|
|
# TODO: Change this if we modify the user model
|
|
form.instance.created_by = self.request.user
|
|
return super().form_valid(form)
|
|
|
|
|
|
# TODO : only the creator can edit the election and view the admin panel
|
|
class ElectionAdminView(DetailView):
|
|
model = Election
|
|
template_name = "elections/election_admin.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs.update({"current_time": timezone.now()})
|
|
return super().get_context_data(**kwargs)
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().prefetch_related("questions__options")
|
|
|
|
|
|
class ElectionUpdateView(SuccessMessageMixin, UpdateView):
|
|
model = Election
|
|
fields = ["name", "description", "start_date", "end_date"]
|
|
success_message = _("Élection modifiée avec succès !")
|
|
template_name = "elections/election_update.html"
|
|
|
|
def get_success_url(self):
|
|
return reverse("election.admin", args=[self.object.pk])
|
|
|
|
def get_queryset(self):
|
|
# On ne peut plus modifier une élection déjà comptée
|
|
return super().get_queryset().filter(tallied=False, archived=False)
|
|
|
|
|
|
class ElectionTallyView(SuccessMessageMixin, SingleObjectMixin, RedirectView):
|
|
model = Election
|
|
pattern_name = "election.admin"
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().prefetch_related("questions__options")
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
election = self.get_object()
|
|
options, questions = [], []
|
|
for q in election.questions.all():
|
|
max_votes = 0
|
|
for o in q.options.all():
|
|
o.nb_votes = o.voters.count()
|
|
max_votes = max(max_votes, o.nb_votes)
|
|
options.append(o)
|
|
|
|
q.max_votes = max_votes
|
|
questions.append(q)
|
|
|
|
Option.objects.bulk_update(options, ["nb_votes"])
|
|
Question.objects.bulk_update(questions, ["max_votes"])
|
|
election.tallied = True
|
|
election.save()
|
|
messages.success(request, _("Élection dépouillée avec succès !"))
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
|
|
class ElectionChangePublicationView(
|
|
SuccessMessageMixin, SingleObjectMixin, RedirectView
|
|
):
|
|
model = Election
|
|
pattern_name = "election.admin"
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
election = self.get_object()
|
|
election.results_public = not election.results_public
|
|
election.save()
|
|
messages.success(
|
|
request,
|
|
_("Élection publiée avec succès !")
|
|
if election.results_public
|
|
else _("Élection dépubliée avec succès !"),
|
|
)
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
|
|
class ElectionArchiveView(SuccessMessageMixin, SingleObjectMixin, RedirectView):
|
|
model = Election
|
|
pattern_name = "election.admin"
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
election = self.get_object()
|
|
election.archived = True
|
|
election.save()
|
|
messages.success(request, _("Élection archivée avec succès !"))
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
|
|
class ElectionView(DetailView):
|
|
model = Election
|
|
template_name = "elections/election.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
if self.object.tallied:
|
|
options_qs = Option.objects.annotate(nb_votes=Count("voters"))
|
|
questions = self.election.question.prefetch_related(
|
|
Prefetch("options", queryset=options_qs)
|
|
)
|
|
context["questions"] = questions
|
|
|
|
return context
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(archived=False)
|
|
|
|
|
|
class VoteView(SuccessMessageMixin, DetailView):
|
|
model = Question
|
|
template_name = "elections/vote.html"
|
|
|
|
def get_queryset(self):
|
|
# On ne peut voter que si l'élection n'a pas été comptée
|
|
return (
|
|
super()
|
|
.get_queryset()
|
|
.filter(election__tallied=False, election__archived=False)
|
|
.select_related("election")
|
|
)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
vote_form = OptionFormSet(instance=self.object)
|
|
|
|
return self.render_to_response(self.get_context_data(formset=vote_form))
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
vote_form = OptionFormSet(self.request.POST, instance=self.object)
|
|
|
|
# We record the cast votes
|
|
for v in vote_form:
|
|
v.record_vote(self.request.user)
|
|
|
|
messages.success(self.request, _("Votre vote a bien été enregistré !"))
|
|
|
|
return HttpResponseRedirect(
|
|
reverse("election.view", args=[self.object.election.pk])
|
|
+ f"#q_{self.object.pk}"
|
|
)
|