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() 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 )