On rajoute une validation pour les formsets selon le type de question, et on rajoute le vote uninominal

This commit is contained in:
Tom Hubrecht 2021-03-19 22:24:27 +01:00
parent 4a99c3d6f5
commit d2161a70d7
6 changed files with 87 additions and 9 deletions

View file

@ -0,0 +1,23 @@
# Generated by Django 2.2.19 on 2021-03-19 15:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0011_question_type"),
]
operations = [
migrations.AlterField(
model_name="question",
name="type",
field=models.CharField(
choices=[("assentiment", "Assentiment"), ("uninominal", "Uninominal")],
default="assentiment",
max_length=11,
verbose_name="type de question",
),
),
]

View file

@ -8,8 +8,9 @@ from .staticdefs import (
CONNECTION_METHODS, CONNECTION_METHODS,
QUESTION_TYPES, QUESTION_TYPES,
TALLY_FUNCTIONS, TALLY_FUNCTIONS,
VALIDATE_FUNCTIONS,
) )
from .utils import CastFunctions, TallyFunctions, choices_length from .utils import CastFunctions, TallyFunctions, ValidateFunctions, choices_length
# ############################################################################# # #############################################################################
# Models regarding an election # Models regarding an election
@ -77,6 +78,10 @@ class Question(models.Model):
blank=True, blank=True,
) )
def is_form_valid(self, vote_form):
validate_function = getattr(ValidateFunctions, VALIDATE_FUNCTIONS[self.type])
return vote_form.is_valid() and validate_function(vote_form)
def cast_ballot(self, user, vote_form): def cast_ballot(self, user, vote_form):
cast_function = getattr(CastFunctions, CAST_FUNCTIONS[self.type]) cast_function = getattr(CastFunctions, CAST_FUNCTIONS[self.type])
cast_function(user, vote_form) cast_function(user, vote_form)

View file

@ -20,6 +20,7 @@ CONNECTION_METHODS = {
QUESTION_TYPES = [ QUESTION_TYPES = [
("assentiment", _("Assentiment")), ("assentiment", _("Assentiment")),
("uninominal", _("Uninominal")),
] ]
VOTE_RULES = { VOTE_RULES = {
@ -27,13 +28,24 @@ VOTE_RULES = {
"Le mode de scrutin pour cette question est un vote par assentiment. " "Le mode de scrutin pour cette question est un vote par assentiment. "
"Vous pouvez donc sélectionner autant d'options que vous souhaitez. " "Vous pouvez donc sélectionner autant d'options que vous souhaitez. "
"Vous pouvez également ne sélectionner aucune option." "Vous pouvez également ne sélectionner aucune option."
) ),
"uninominal": _(
"Le mode de scrutin pour cette question est un vote uninominal. "
"Vous ne pouvez donc sélectionner qu'une seule option."
),
} }
CAST_FUNCTIONS = { CAST_FUNCTIONS = {
"assentiment": "cast_select", "assentiment": "cast_select",
"uninominal": "cast_select",
} }
TALLY_FUNCTIONS = { TALLY_FUNCTIONS = {
"assentiment": "tally_select", "assentiment": "tally_select",
"uninominal": "tally_select",
}
VALIDATE_FUNCTIONS = {
"assentiment": "always_true",
"uninominal": "unique_selected",
} }

View file

@ -31,7 +31,6 @@ class CastFunctions:
def cast_select(user, vote_form): def cast_select(user, vote_form):
"""On enregistre un vote classique""" """On enregistre un vote classique"""
vote_form.full_clean()
selected, n_selected = [], [] selected, n_selected = [], []
for v in vote_form: for v in vote_form:
if v.cleaned_data["selected"]: if v.cleaned_data["selected"]:
@ -64,6 +63,33 @@ class TallyFunctions:
Option.objects.bulk_update(options, ["nb_votes"]) Option.objects.bulk_update(options, ["nb_votes"])
class ValidateFunctions:
"""Classe pour valider les formsets selon le type de question"""
def always_true(vote_form):
"""Retourne True pour les votes sans validation particulière"""
return True
def unique_selected(vote_form):
"""Vérifie qu'une seule option est choisie"""
print("toto")
nb_selected = 0
for v in vote_form:
nb_selected += v.cleaned_data["selected"]
if nb_selected == 0:
vote_form._non_form_errors.append(
ValidationError(_("Vous devez sélectionnner une option."))
)
return False
elif nb_selected > 1:
vote_form._non_form_errors.append(
ValidationError(_("Vous ne pouvez pas sélectionner plus d'une option."))
)
return False
return True
# ############################################################################# # #############################################################################
# Fonctions pour importer une liste de votant·e·s # Fonctions pour importer une liste de votant·e·s
# ############################################################################# # #############################################################################

View file

@ -410,10 +410,12 @@ class VoteView(OpenElectionOnlyMixin, DetailView):
self.object = self.get_object() self.object = self.get_object()
vote_form = OptionFormSet(self.request.POST, instance=self.object) vote_form = OptionFormSet(self.request.POST, instance=self.object)
# On enregistre le vote if self.object.is_form_valid(vote_form):
self.object.cast_ballot(self.request.user, vote_form) # On enregistre le vote
self.object.voters.add(self.request.user) self.object.cast_ballot(self.request.user, vote_form)
self.object.voters.add(self.request.user)
messages.success(self.request, _("Votre choix a bien été enregistré !"))
messages.success(self.request, _("Votre choix a bien été enregistré !")) return HttpResponseRedirect(self.get_success_url())
else:
return HttpResponseRedirect(self.get_success_url()) return self.render_to_response(self.get_context_data(formset=vote_form))

View file

@ -1,3 +1,13 @@
{% if formset.non_form_errors %}
<div class="message is-danger">
<p class="message-body">
{% for error in formset.non_form_errors %}
{{ error }}
{% endfor %}
</p>
</div>
{% endif %}
{{ formset.management_form }} {{ formset.management_form }}
{% for form in formset %} {% for form in formset %}
{% include 'forms/form.html' %} {% include 'forms/form.html' %}