kadenios/elections/forms.py

164 lines
5 KiB
Python

from translated_fields import language_code_formfield_callback
from django import forms
from django.forms.models import inlineformset_factory
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from .models import Election, Option, Question
from .utils import check_csv
class ElectionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
def clean(self):
cleaned_data = super().clean()
assert cleaned_data is not None
if cleaned_data["start_date"] < timezone.now():
self.add_error(
"start_date", _("Impossible de faire débuter l'élection dans le passé")
)
elif cleaned_data["start_date"] >= cleaned_data["end_date"]:
self.add_error(
"end_date", _("Impossible de terminer l'élection avant de la commencer")
)
if self.instance.sent_mail and not cleaned_data["restricted"]:
self.add_error(
"restricted",
_(
"Le mail d'annonce a déjà été envoyé, il n'est pas possible "
"d'ouvrir l'élection à tout le monde"
),
)
return cleaned_data
class Meta:
model = Election
fields = [
*Election.name.fields,
"start_date",
"end_date",
*Election.description.fields,
"restricted",
*Election.vote_restrictions.fields,
]
widgets = {
"description_en": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
"description_fr": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
"vote_restrictions_en": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
"vote_restrictions_fr": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
}
class UploadVotersForm(forms.Form):
csv_file = forms.FileField(label=_("Sélectionnez un fichier .csv"))
def clean_csv_file(self):
csv_file = self.cleaned_data["csv_file"]
if csv_file.name.lower().endswith(".csv"):
for error in check_csv(csv_file):
self.add_error(None, error)
else:
self.add_error(
None,
_("Extension de fichier invalide, il faut un fichier au format CSV."),
)
csv_file.seek(0)
return csv_file
class VoterMailForm(forms.Form):
objet = forms.CharField(label=_("Objet"))
message = forms.CharField(widget=forms.Textarea)
class QuestionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
class Meta:
model = Question
fields = [*Question.text.fields, "type"]
widgets = {"text_fr": forms.TextInput, "text_en": forms.TextInput}
class OptionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
class Meta:
model = Option
fields = [*Option.text.fields, "abbreviation"]
widgets = {"text_fr": forms.TextInput, "text_en": forms.TextInput}
help_texts = {
"abbreviation": _(
"L'abréviation est optionnelle et sert à identifier plus facilement les "
"différentes options. Elle est affiché sans espaces et en majuscules."
)
}
class DeleteVoteForm(forms.Form):
def __init__(self, **kwargs):
voter = kwargs.pop("voter", None)
super().__init__(**kwargs)
if voter is not None:
self.fields["delete"].label = _("Supprimer le vote de {} ({}) ?").format(
voter.full_name, voter.base_username
)
delete = forms.ChoiceField(
label=_("Supprimer"), choices=(("non", _("Non")), ("oui", _("Oui")))
)
class SelectVoteForm(forms.ModelForm):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# We set the option's text as the label for the checkbox
instance = kwargs.get("instance", None)
if instance is not None:
self.fields["selected"].label = str(instance)
selected = forms.BooleanField(required=False)
class Meta:
model = Option
fields = []
exclude = ["voters"]
class RankVoteForm(forms.ModelForm):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# We set the option's text as the label for the rank
instance = kwargs.get("instance", None)
if instance is not None:
self.fields["rank"].label = str(instance)
rank = forms.IntegerField(required=False)
class Meta:
model = Option
fields = []
exclude = ["voters"]
class BallotFormset:
select = inlineformset_factory(
Question, Option, extra=0, form=SelectVoteForm, can_delete=False
)
rank = inlineformset_factory(
Question, Option, extra=0, form=RankVoteForm, can_delete=False
)