summaryrefslogtreecommitdiff
path: root/django/contrib/auth/forms.py
diff options
context:
space:
mode:
authorFabian Braun <fsbraun@gmx.de>2024-01-23 16:35:36 +0100
committerNatalia <124304+nessita@users.noreply.github.com>2024-02-20 10:50:49 -0300
commitf64c528c17af91333fc6e96d91b5f13c0fb647d8 (patch)
treea193811bd1643ad280f6ed235302f425059b9f3d /django/contrib/auth/forms.py
parent31314980be428c0ab8a6cf40cce0a0c17ead8ec6 (diff)
Refs #34429 -- Created `SetPasswordMixin` to reuse password validation logic in auth forms.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'django/contrib/auth/forms.py')
-rw-r--r--django/contrib/auth/forms.py173
1 files changed, 76 insertions, 97 deletions
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index 061dc81b42..db51f72f3b 100644
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -89,27 +89,65 @@ class UsernameField(forms.CharField):
}
-class BaseUserCreationForm(forms.ModelForm):
+class SetPasswordMixin:
"""
- A form that creates a user, with no privileges, from the given username and
- password.
+ Form mixin that validates and sets a password for a user.
"""
error_messages = {
"password_mismatch": _("The two password fields didn’t match."),
}
- password1 = forms.CharField(
- label=_("Password"),
- strip=False,
- widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
- help_text=password_validation.password_validators_help_text_html(),
- )
- password2 = forms.CharField(
- label=_("Password confirmation"),
- widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
- strip=False,
- help_text=_("Enter the same password as before, for verification."),
- )
+
+ @staticmethod
+ def create_password_fields(label1=_("Password"), label2=_("Password confirmation")):
+ password1 = forms.CharField(
+ label=label1,
+ strip=False,
+ widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
+ help_text=password_validation.password_validators_help_text_html(),
+ )
+ password2 = forms.CharField(
+ label=label2,
+ widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
+ strip=False,
+ help_text=_("Enter the same password as before, for verification."),
+ )
+ return password1, password2
+
+ def validate_passwords(
+ self, password1_field_name="password1", password2_field_name="password2"
+ ):
+ password1 = self.cleaned_data.get(password1_field_name)
+ password2 = self.cleaned_data.get(password2_field_name)
+ if password1 and password2 and password1 != password2:
+ error = ValidationError(
+ self.error_messages["password_mismatch"],
+ code="password_mismatch",
+ )
+ self.add_error(password2_field_name, error)
+
+ def validate_password_for_user(self, user, password_field_name="password2"):
+ password = self.cleaned_data.get(password_field_name)
+ if password:
+ try:
+ password_validation.validate_password(password, user)
+ except ValidationError as error:
+ self.add_error(password_field_name, error)
+
+ def set_password_and_save(self, user, password_field_name="password1", commit=True):
+ user.set_password(self.cleaned_data[password_field_name])
+ if commit:
+ user.save()
+ return user
+
+
+class BaseUserCreationForm(SetPasswordMixin, forms.ModelForm):
+ """
+ A form that creates a user, with no privileges, from the given username and
+ password.
+ """
+
+ password1, password2 = SetPasswordMixin.create_password_fields()
class Meta:
model = User
@@ -123,34 +161,21 @@ class BaseUserCreationForm(forms.ModelForm):
"autofocus"
] = True
- def clean_password2(self):
- password1 = self.cleaned_data.get("password1")
- password2 = self.cleaned_data.get("password2")
- if password1 and password2 and password1 != password2:
- raise ValidationError(
- self.error_messages["password_mismatch"],
- code="password_mismatch",
- )
- return password2
+ def clean(self):
+ self.validate_passwords()
+ return super().clean()
def _post_clean(self):
super()._post_clean()
# Validate the password after self.instance is updated with form data
# by super().
- password = self.cleaned_data.get("password2")
- if password:
- try:
- password_validation.validate_password(password, self.instance)
- except ValidationError as error:
- self.add_error("password2", error)
+ self.validate_password_for_user(self.instance)
def save(self, commit=True):
user = super().save(commit=False)
- user.set_password(self.cleaned_data["password1"])
- if commit:
- user.save()
- if hasattr(self, "save_m2m"):
- self.save_m2m()
+ user = self.set_password_and_save(user, commit=commit)
+ if commit and hasattr(self, "save_m2m"):
+ self.save_m2m()
return user
@@ -383,48 +408,27 @@ class PasswordResetForm(forms.Form):
)
-class SetPasswordForm(forms.Form):
+class SetPasswordForm(SetPasswordMixin, forms.Form):
"""
A form that lets a user set their password without entering the old
password
"""
- error_messages = {
- "password_mismatch": _("The two password fields didn’t match."),
- }
- new_password1 = forms.CharField(
- label=_("New password"),
- widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
- strip=False,
- help_text=password_validation.password_validators_help_text_html(),
- )
- new_password2 = forms.CharField(
- label=_("New password confirmation"),
- strip=False,
- widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
+ new_password1, new_password2 = SetPasswordMixin.create_password_fields(
+ label1=_("New password"), label2=_("New password confirmation")
)
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
- def clean_new_password2(self):
- password1 = self.cleaned_data.get("new_password1")
- password2 = self.cleaned_data.get("new_password2")
- if password1 and password2 and password1 != password2:
- raise ValidationError(
- self.error_messages["password_mismatch"],
- code="password_mismatch",
- )
- password_validation.validate_password(password2, self.user)
- return password2
+ def clean(self):
+ self.validate_passwords("new_password1", "new_password2")
+ self.validate_password_for_user(self.user, "new_password2")
+ return super().clean()
def save(self, commit=True):
- password = self.cleaned_data["new_password1"]
- self.user.set_password(password)
- if commit:
- self.user.save()
- return self.user
+ return self.set_password_and_save(self.user, "new_password1", commit=commit)
class PasswordChangeForm(SetPasswordForm):
@@ -462,52 +466,27 @@ class PasswordChangeForm(SetPasswordForm):
return old_password
-class AdminPasswordChangeForm(forms.Form):
+class AdminPasswordChangeForm(SetPasswordMixin, forms.Form):
"""
A form used to change the password of a user in the admin interface.
"""
- error_messages = {
- "password_mismatch": _("The two password fields didn’t match."),
- }
required_css_class = "required"
- password1 = forms.CharField(
- label=_("Password"),
- widget=forms.PasswordInput(
- attrs={"autocomplete": "new-password", "autofocus": True}
- ),
- strip=False,
- help_text=password_validation.password_validators_help_text_html(),
- )
- password2 = forms.CharField(
- label=_("Password (again)"),
- widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
- strip=False,
- help_text=_("Enter the same password as before, for verification."),
- )
+ password1, password2 = SetPasswordMixin.create_password_fields()
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
+ self.fields["password1"].widget.attrs["autofocus"] = True
- def clean_password2(self):
- password1 = self.cleaned_data.get("password1")
- password2 = self.cleaned_data.get("password2")
- if password1 and password2 and password1 != password2:
- raise ValidationError(
- self.error_messages["password_mismatch"],
- code="password_mismatch",
- )
- password_validation.validate_password(password2, self.user)
- return password2
+ def clean(self):
+ self.validate_passwords()
+ self.validate_password_for_user(self.user)
+ return super().clean()
def save(self, commit=True):
"""Save the new password."""
- password = self.cleaned_data["password1"]
- self.user.set_password(password)
- if commit:
- self.user.save()
- return self.user
+ return self.set_password_and_save(self.user, commit=commit)
@property
def changed_data(self):