fix: bad value for blank vote and better flow for invalid form

* Add an error message when looking at a public election without being logged in
* Add correct value for blank vote on single vote field
* Redirect to view with an error message if an invalid form has been submitted
This commit is contained in:
2026-01-14 11:30:04 +01:00
parent 8c6f7c82c9
commit 2744282fd8
4 changed files with 55 additions and 29 deletions

View File

@@ -60,8 +60,6 @@ class CandidateForm(forms.ModelForm):
class VoteForm(forms.Form):
def __init__(self, election: Election, user: User, *args, **kwargs):
super().__init__(*args, **kwargs)
if not election.can_vote(user):
return
for role in election.roles.all():
cand = role.candidatures
if role.max_choice > 1:
@@ -74,6 +72,7 @@ class VoteForm(forms.Form):
required=False,
widget=forms.RadioSelect(),
empty_label=_("Blank vote"),
blank=True,
)

View File

@@ -14,6 +14,11 @@
{% block content %}
<h3 class="election__title">{{ election.title }}</h3>
{% if user.is_anonymous %}
<div class="alert alert-red">
{% trans %}You are not logged in, candidate pictures won't display for privacy reasons.{% endtrans %}
</div>
{% endif %}
<p class="election__description">{{ election.description }}</p>
<hr>
<section class="election_details">
@@ -117,7 +122,7 @@
{%- if role.max_choice == 1 and show_vote_buttons %}
<div class="radio-btn">
{% set input_id = "blank_vote_" + role.id|string %}
<input id="{{ input_id }}" type="radio" name="{{ role.title }}">
<input id="{{ input_id }}" type="radio" name="{{ role.title }}" value="" checked>
<label for="{{ input_id }}">
<span>{% trans %}Choose blank vote{% endtrans %}</span>
</label>
@@ -185,6 +190,7 @@
</table>
</form>
</section>
{% if not user.is_anonymous %}
<section class="buttons">
{%- if (election.can_candidate(user) and election.is_candidature_active) or (user.can_edit(election) and election.is_vote_editable) %}
<a class="button" href="{{ url('election:candidate', election_id=object.id) }}">{% trans %}Candidate{% endtrans %}</a>
@@ -207,4 +213,5 @@
<button class="button button_send" form="vote-form">{% trans %}Submit the vote !{% endtrans %}</button>
</section>
{%- endif %}
{% endif %}
{% endblock %}

View File

@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING
from cryptography.utils import cached_property
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
@@ -10,8 +11,9 @@ from django.contrib.auth.mixins import (
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import QuerySet
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
@@ -53,7 +55,7 @@ class ElectionListArchivedView(CanViewMixin, ListView):
class ElectionDetailView(CanViewMixin, DetailView):
"""Details an election responsability by responsability."""
"""Details an election responsibility by responsibility."""
model = Election
template_name = "election/election_detail.jinja"
@@ -83,7 +85,7 @@ class ElectionDetailView(CanViewMixin, DetailView):
return super().get(request, *arg, **kwargs)
def get_context_data(self, **kwargs):
"""Add additionnal data to the template."""
"""Add additional data to the template."""
user: User = self.request.user
return super().get_context_data(**kwargs) | {
"election_form": VoteForm(self.object, user),
@@ -101,7 +103,7 @@ class ElectionDetailView(CanViewMixin, DetailView):
class VoteFormView(LoginRequiredMixin, UserPassesTestMixin, FormView):
"""Alows users to vote."""
"""Allows users to vote."""
form_class = VoteForm
template_name = "election/election_detail.jinja"
@@ -111,6 +113,9 @@ class VoteFormView(LoginRequiredMixin, UserPassesTestMixin, FormView):
return get_object_or_404(Election, pk=self.kwargs["election_id"])
def test_func(self):
if not self.election.can_vote(self.request.user):
return False
groups = set(self.election.vote_groups.values_list("id", flat=True))
if (
settings.SITH_GROUP_SUBSCRIBERS_ID in groups
@@ -150,11 +155,17 @@ class VoteFormView(LoginRequiredMixin, UserPassesTestMixin, FormView):
self.vote(data)
return super().form_valid(form)
def form_invalid(self, form):
messages.error(self.request, _("Form is invalid"))
return redirect(
reverse("election:detail", kwargs={"election_id": self.election.id}),
)
def get_success_url(self, **kwargs):
return reverse_lazy("election:detail", kwargs={"election_id": self.election.id})
def get_context_data(self, **kwargs):
"""Add additionnal data to the template."""
"""Add additional data to the template."""
kwargs = super().get_context_data(**kwargs)
kwargs["object"] = self.election
kwargs["election"] = self.election

View File

@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-19 23:10+0100\n"
"POT-Creation-Date: 2026-01-14 11:34+0100\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
@@ -4108,6 +4108,11 @@ msgstr "Candidater"
msgid "Candidature are closed for this election"
msgstr "Les candidatures sont fermées pour cette élection"
#: election/templates/election/election_detail.jinja
msgid ""
"You are not logged in, candidate pictures won't display for privacy reasons."
msgstr "Vous n'êtes pas connecté, les photos des candidats ne s'afficheront pas pour des raisons de respect de la vie privée."
#: election/templates/election/election_detail.jinja
msgid "Polls close "
msgstr "Votes fermés"
@@ -4183,6 +4188,10 @@ msgstr "au"
msgid "Polls open from"
msgstr "Votes ouverts du"
#: election/views.py
msgid "Form is invalid"
msgstr "Formulaire invalide"
#: forum/models.py
msgid "is a category"
msgstr "est une catégorie"