Source code for users_api.forms

from typing import Any

from django import forms
from django.contrib.auth import (
    authenticate,
    get_user_model,
    login,
    password_validation,
)
from django.contrib.auth.forms import SetPasswordForm, UsernameField
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy
from rest_framework import status
from utils.password_requirements import is_password_valid

from users_api.models import AuthenticationLog

from .models import WdaeUser


[docs] class WdaeResetPasswordForm(SetPasswordForm): """A form for users to reset their password when forgotten.""" error_messages = { "password_invalid": gettext_lazy( "Your password is either too short " "(less than 10 symbols) or too weak.", ), "password_mismatch": gettext_lazy( "The two passwords do not match.", ), }
[docs] def clean_new_password2(self) -> str: password2 = super().clean_new_password2() if not is_password_valid(password2): raise ValidationError( self.error_messages["password_invalid"], code="password_invalid", ) return password2
[docs] class WdaeRegisterPasswordForm(WdaeResetPasswordForm): """A form for users to set their password when registered in the system.""" new_password1 = forms.CharField( label=gettext_lazy("Password"), widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), strip=False, help_text=password_validation.password_validators_help_text_html(), ) new_password2 = forms.CharField( label=gettext_lazy("Password confirmation"), strip=False, widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), )
[docs] class WdaeLoginForm(forms.Form): """A form for users to log in to the system.""" username = UsernameField( widget=forms.TextInput( attrs={"autofocus": True, "tabindex": 1}, ), ) password = forms.CharField( label=gettext_lazy("Password"), strip=False, widget=forms.PasswordInput( attrs={"autocomplete": "current-password", "tabindex": 2}, ), ) error_messages = { "invalid_credentials": gettext_lazy( "Invalid login credentials.", ), "no_password": gettext_lazy( "Password not provided.", ), "inactive": gettext_lazy( "User is inactive.", ), "no_user": gettext_lazy( "User not found.", ), "no_username": gettext_lazy( "Username not provided.", ), } def __init__(self, request: Any = None, **kwargs: Any): self.request = request super().__init__(**kwargs) # Set the max length and label for the "username" field. user_model = get_user_model() self.username_field = \ user_model._meta.get_field(user_model.USERNAME_FIELD) username_max_length = \ self.username_field.max_length or 254 # type: ignore self.fields[ "username"].max_length = username_max_length # type: ignore self.fields["username"].widget.attrs["maxlength"] = username_max_length if self.fields["username"].label is None: self.fields["username"].label = capfirst( self.username_field.verbose_name) # type: ignore self.status_code = None self.user_cache = None
[docs] def confirm_login_allowed(self, user: WdaeUser) -> None: if AuthenticationLog.is_user_locked_out(user.email): self.status_code = status.HTTP_403_FORBIDDEN raise AuthenticationLog.get_locked_out_error(user.email) if not user.is_active: self.status_code = status.HTTP_403_FORBIDDEN raise ValidationError( self.error_messages["inactive"], code="inactive", )
[docs] def clean(self) -> dict: username = self.cleaned_data.get("username") user_model = get_user_model() if username is None or username == "": self.status_code = status.HTTP_400_BAD_REQUEST raise ValidationError( self.error_messages["no_username"], code="no_username", ) try: self.user_cache = user_model.objects.get( # type: ignore email__iexact=username, ) except ObjectDoesNotExist: self.status_code = status.HTTP_404_NOT_FOUND raise ValidationError( self.error_messages["no_user"], code="no_user", ) from None assert self.user_cache is not None self.confirm_login_allowed(self.user_cache) password = self.cleaned_data.get("password") if password is None or password == "": self.status_code = status.HTTP_400_BAD_REQUEST raise ValidationError( self.error_messages["no_password"], code="no_password", ) username = self.user_cache.email self.user_cache = authenticate( self.request, username=username, password=password, ) if self.user_cache is None: AuthenticationLog.log_authentication_attempt( username, failed=True, ) if AuthenticationLog.is_user_locked_out(username): self.status_code = status.HTTP_403_FORBIDDEN raise AuthenticationLog.get_locked_out_error(username) self.status_code = status.HTTP_401_UNAUTHORIZED raise ValidationError( self.error_messages["invalid_credentials"], code="invalid_credentials", ) login(self.request, self.user_cache) AuthenticationLog.log_authentication_attempt(username, failed=False) return self.cleaned_data
[docs] def get_status_code(self) -> Any: if self.is_valid(): return status.HTTP_200_OK assert self.status_code is not None return self.status_code
[docs] class WdaePasswordForgottenForm(forms.Form): email = forms.EmailField( label="Email", max_length=254, widget=forms.EmailInput(attrs={"autocomplete": "email"}), )