On restreint l'accès au vote

This commit is contained in:
Tom Hubrecht 2020-12-20 18:50:38 +01:00
parent 5865583ace
commit e704e2a155
7 changed files with 128 additions and 24 deletions

View file

@ -21,7 +21,7 @@ class ElectionForm(forms.ModelForm):
class Meta: class Meta:
model = Election model = Election
fields = ["name", "description", "start_date", "end_date"] fields = ["name", "description", "restricted", "start_date", "end_date"]
class QuestionForm(forms.ModelForm): class QuestionForm(forms.ModelForm):

View file

@ -0,0 +1,36 @@
# Generated by Django 2.2.17 on 2020-12-20 16:35
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="user",
name="election",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="registered_voters",
to="elections.Election",
),
),
migrations.AlterField(
model_name="election",
name="created_by",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="elections_created",
to=settings.AUTH_USER_MODEL,
),
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 2.2.17 on 2020-12-20 17:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0002_auto_20201220_1735"),
]
operations = [
migrations.AddField(
model_name="election",
name="restricted",
field=models.BooleanField(
default=True, verbose_name="restreint le vote à une liste de personnes"
),
),
]

View file

@ -0,0 +1,25 @@
# Generated by Django 2.2.17 on 2020-12-20 17:47
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0003_election_restricted"),
]
operations = [
migrations.AlterField(
model_name="user",
name="election",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="registered_voters",
to="elections.Election",
),
),
]

View file

@ -35,7 +35,7 @@ class RestrictAccessMixin(SelectElectionMixin):
return qs.none() return qs.none()
class OpenElectionOnly(RestrictAccessMixin): class OpenElectionOnlyMixin(RestrictAccessMixin):
"""N'autorise la vue que lorsque l'élection est ouverte""" """N'autorise la vue que lorsque l'élection est ouverte"""
def get_filters(self): def get_filters(self):

View file

@ -1,16 +1,8 @@
from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
# #############################################################################
# Modification of the base User Model
# #############################################################################
class User(AbstractUser):
pass
# ############################################################################# # #############################################################################
# Models regarding an election # Models regarding an election
# ############################################################################# # #############################################################################
@ -24,8 +16,16 @@ class Election(models.Model):
start_date = models.DateTimeField(_("date et heure de début")) start_date = models.DateTimeField(_("date et heure de début"))
end_date = models.DateTimeField(_("date et heure de fin")) end_date = models.DateTimeField(_("date et heure de fin"))
restricted = models.BooleanField(
_("restreint le vote à une liste de personnes"), default=True
)
created_by = models.ForeignKey( created_by = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True settings.AUTH_USER_MODEL,
related_name="elections_created",
on_delete=models.SET_NULL,
blank=True,
null=True,
) )
results_public = models.BooleanField(_("résultats publics"), default=False) results_public = models.BooleanField(_("résultats publics"), default=False)
@ -58,7 +58,7 @@ class Option(models.Model):
) )
text = models.TextField(_("texte"), blank=False) text = models.TextField(_("texte"), blank=False)
voters = models.ManyToManyField( voters = models.ManyToManyField(
User, settings.AUTH_USER_MODEL,
related_name="votes", related_name="votes",
) )
# For now, we store the amount of votes received after the election is tallied # For now, we store the amount of votes received after the election is tallied
@ -66,3 +66,26 @@ class Option(models.Model):
class Meta: class Meta:
ordering = ["id"] ordering = ["id"]
# #############################################################################
# Modification of the base User Model
# #############################################################################
class User(AbstractUser):
election = models.ForeignKey(
Election,
related_name="registered_voters",
null=True,
blank=True,
on_delete=models.CASCADE,
)
def can_vote(self, election):
# Si c'est un·e utilisateur·ice CAS, iel peut voter dans les élections
# ouvertes à tou·te·s
if self.election is None:
return not election.restricted
# Pour les élections restreintes, il faut y être associé
return election.restricted and (self.election == election)

View file

@ -2,7 +2,7 @@ from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
# from django.db.models import Count, Prefetch # from django.db.models import Count, Prefetch
from django.http import HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.text import slugify from django.utils.text import slugify
@ -16,7 +16,7 @@ from django.views.generic import (
) )
from .forms import ElectionForm, OptionForm, OptionFormSet, QuestionForm from .forms import ElectionForm, OptionForm, OptionFormSet, QuestionForm
from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnly from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnlyMixin
from .models import Election, Option, Question from .models import Election, Option, Question
# TODO: access control *everywhere* # TODO: access control *everywhere*
@ -268,14 +268,6 @@ class ElectionView(DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs.update({"current_time": timezone.now()}) kwargs.update({"current_time": timezone.now()})
return super().get_context_data(**kwargs) return super().get_context_data(**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): def get_queryset(self):
return ( return (
@ -286,7 +278,7 @@ class ElectionView(DetailView):
) )
class VoteView(OpenElectionOnly, DetailView): class VoteView(OpenElectionOnlyMixin, DetailView):
model = Question model = Question
template_name = "elections/vote.html" template_name = "elections/vote.html"
@ -302,6 +294,14 @@ class VoteView(OpenElectionOnly, DetailView):
return reverse("election.vote", args=[q_next]) return reverse("election.vote", args=[q_next])
def get_object(self):
question = super().get_object()
# Seulement les utilisateur·ice·s ayant le droit de voter dans l'élection
# peuvent voir la page
if not self.request.user.can_vote(question.election):
raise Http404
return question
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
vote_form = OptionFormSet(instance=self.object) vote_form = OptionFormSet(instance=self.object)