mirror of https://github.com/django/django.git
Refs #34429 -- Created `SetPasswordMixin` to reuse password validation logic in auth forms.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
31314980be
commit
f64c528c17
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue