from typing import TYPE_CHECKING from django import forms from django.contrib.auth import authenticate from django.contrib.auth import forms as auth_forms from django.core.validators import validate_email from django.utils.translation import gettext_lazy as _ if TYPE_CHECKING: from elections.typing import User else: from django.contrib.auth import get_user_model User = get_user_model() class ElectionAuthForm(forms.Form): """Adapts Django's AuthenticationForm to allow for an election specific login.""" login = auth_forms.UsernameField(label=_("Identifiant"), max_length=255) password = forms.CharField( label=_("Mot de passe"), strip=False, widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}), ) election_id = forms.IntegerField(widget=forms.HiddenInput()) def __init__(self, request=None, *args, **kwargs): self.request = request self.user_cache = None super().__init__(*args, **kwargs) def clean(self): login = self.cleaned_data.get("login") password = self.cleaned_data.get("password") election_id = self.cleaned_data.get("election_id") if login is not None and password: self.user_cache = authenticate( self.request, login=login, password=password, election_id=election_id, ) if self.user_cache is None: raise self.get_invalid_login_error() return self.cleaned_data def get_user(self): # Necessary API for LoginView return self.user_cache def get_invalid_login_error(self): return forms.ValidationError( _( "Aucun·e électeur·ice avec cet identifiant et mot de passe n'existe " "pour cette élection. Vérifiez que les informations rentrées sont " "correctes, les champs sont sensibles à la casse." ), code="invalid_login", ) class PwdResetForm(auth_forms.PasswordResetForm): """Restricts the search for password users, i.e. whose username starts with pwd__.""" def get_users(self, email): users = super().get_users(email) return (u for u in users if u.username.split("__")[0] == "pwd") class PwdUserForm(forms.ModelForm): """ Allows for the creation of a Password Account given the email, base username and full name. """ email = forms.EmailField( label=_("Email"), required=True, validators=[validate_email] ) def clean(self): # On rajoute le préfixe signifiant qu'on crée un compte avec mot de passe cleaned_data = super().clean() cleaned_data["username"] = "pwd__" + cleaned_data["username"] return cleaned_data class Meta: model = User fields = ["username", "full_name", "email"] class UserAdminForm(forms.Form): """ Allows to select an user and give them some admin permissions """ username = forms.CharField(label=_("Nom d'utilisateur"), max_length=150) full_admin = forms.BooleanField( label=_("Passer administrateur de Kadenios"), required=False ) faq_admin = forms.BooleanField( label=_("Autoriser à créer des FAQs"), required=False ) election_admin = forms.BooleanField( label=_("Autoriser à créer des élections"), required=False ) def clean(self): cleaned_data = super().clean() username = cleaned_data["username"] if not username[:5] in ["cas__", "pwd__"]: self.add_error( "username", _( "Format de login invalide, seuls les comptes CAS ou avec " "mot de passe sont modifiables" ), ) elif not User.objects.filter(username=username).exists(): self.add_error("username", _("Pas d'utilisateur·rice avec ce login")) return cleaned_data