diff --git a/src/core/forms/__init__.py b/src/core/forms/__init__.py index e1ae805aa9..c7a560a7b2 100644 --- a/src/core/forms/__init__.py +++ b/src/core/forms/__init__.py @@ -29,6 +29,7 @@ NotificationForm, OrcidAffiliationForm, OrganizationNameForm, + PasswordChangeForm, PasswordResetForm, PressJournalAttrForm, QuickUserForm, diff --git a/src/core/forms/forms.py b/src/core/forms/forms.py index 8b0f98d056..ca5e52e96d 100755 --- a/src/core/forms/forms.py +++ b/src/core/forms/forms.py @@ -246,6 +246,62 @@ def save(self, commit=True): return user +class PasswordChangeForm(forms.Form): + """ + A form for changing the password of an already-authenticated user. + + Validates the current password, confirms the two new-password fields + match, and runs the press password policy check so that all failures + are surfaced as inline form errors rather than disappearing toast + messages. + """ + + old_password = forms.CharField( + label=_("Current password"), + widget=forms.PasswordInput, + ) + new_password_one = forms.CharField( + label=_("New password"), + widget=forms.PasswordInput, + ) + new_password_two = forms.CharField( + label=_("Confirm new password"), + widget=forms.PasswordInput, + ) + + def __init__(self, *args, user=None, request=None, **kwargs): + super().__init__(*args, **kwargs) + self.user = user + self.request = request + + def clean_old_password(self): + value = self.cleaned_data.get("old_password") + if self.user and not self.user.check_password(value): + raise ValidationError(_("Current password is incorrect.")) + return value + + def clean(self): + cleaned = super().clean() + new_one = cleaned.get("new_password_one") + new_two = cleaned.get("new_password_two") + + if new_one and new_two and new_one != new_two: + self.add_error("new_password_two", _("Passwords do not match.")) + + if new_one and self.user and self.request: + problems = self.user.password_policy_check(self.request, new_one) + for problem in problems: + self.add_error( + "new_password_one", _("Password not updated: ") + str(problem) + ) + + return cleaned + + def save(self): + self.user.set_password(self.cleaned_data["new_password_one"]) + self.user.save() + + class EditAccountForm(forms.ModelForm): """ A form for modifying profile details of an account, such as diff --git a/src/core/locales/cy/LC_MESSAGES/django.po b/src/core/locales/cy/LC_MESSAGES/django.po index 2c31fb4942..3eb2bbaed2 100644 --- a/src/core/locales/cy/LC_MESSAGES/django.po +++ b/src/core/locales/cy/LC_MESSAGES/django.po @@ -413,11 +413,11 @@ msgid "Password updated." msgstr "Canllaw Cyfrinair " #: src/core/views.py:613 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:629 diff --git a/src/core/locales/de/LC_MESSAGES/django.po b/src/core/locales/de/LC_MESSAGES/django.po index dceda8cb60..fd4fe54852 100644 --- a/src/core/locales/de/LC_MESSAGES/django.po +++ b/src/core/locales/de/LC_MESSAGES/django.po @@ -427,11 +427,11 @@ msgid "Password updated." msgstr "Passwort aktualisiert." #: src/core/views.py:613 -msgid "Passwords do not match" -msgstr "Passwörter stimmen nicht überein" +msgid "Passwords do not match." +msgstr "Passwörter stimmen nicht überein." #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "Das alte Passwort ist nicht korrekt." #: src/core/views.py:629 diff --git a/src/core/locales/en_us/LC_MESSAGES/django.po b/src/core/locales/en_us/LC_MESSAGES/django.po index b42f502c96..fa124cfbed 100644 --- a/src/core/locales/en_us/LC_MESSAGES/django.po +++ b/src/core/locales/en_us/LC_MESSAGES/django.po @@ -309,10 +309,10 @@ msgstr "" msgid "Password updated." msgstr "" #: src/core/views.py:467 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:470 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:480 msgid "Successfully subscribed to article notifications." diff --git a/src/core/locales/es/LC_MESSAGES/django.po b/src/core/locales/es/LC_MESSAGES/django.po index dcc05e8e0e..fce0253e58 100644 --- a/src/core/locales/es/LC_MESSAGES/django.po +++ b/src/core/locales/es/LC_MESSAGES/django.po @@ -409,11 +409,11 @@ msgid "Password updated." msgstr "" #: src/core/views.py:613 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:629 diff --git a/src/core/locales/fr/LC_MESSAGES/django.po b/src/core/locales/fr/LC_MESSAGES/django.po index 61666b4637..35803c9311 100755 --- a/src/core/locales/fr/LC_MESSAGES/django.po +++ b/src/core/locales/fr/LC_MESSAGES/django.po @@ -417,11 +417,11 @@ msgid "Password updated." msgstr "Mot de passe" #: src/core/views.py:613 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:629 diff --git a/src/core/locales/it/LC_MESSAGES/django.po b/src/core/locales/it/LC_MESSAGES/django.po index f55827eabf..8ea6ea7514 100644 --- a/src/core/locales/it/LC_MESSAGES/django.po +++ b/src/core/locales/it/LC_MESSAGES/django.po @@ -413,11 +413,11 @@ msgid "Password updated." msgstr "Guida password" #: src/core/views.py:613 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:629 diff --git a/src/core/locales/nl/LC_MESSAGES/django.po b/src/core/locales/nl/LC_MESSAGES/django.po index 4bbada27ed..b20b494a0e 100644 --- a/src/core/locales/nl/LC_MESSAGES/django.po +++ b/src/core/locales/nl/LC_MESSAGES/django.po @@ -412,11 +412,11 @@ msgid "Password updated." msgstr "Wachtwoordgids" #: src/core/views.py:613 -msgid "Passwords do not match" +msgid "Passwords do not match." msgstr "" #: src/core/views.py:618 -msgid "Old password is not correct." +msgid "Current password is incorrect." msgstr "" #: src/core/views.py:629 diff --git a/src/core/views.py b/src/core/views.py index 9135ed4fed..3ffe1c4ab6 100755 --- a/src/core/views.py +++ b/src/core/views.py @@ -552,6 +552,7 @@ def edit_profile(request): """ user = request.user form = forms.EditAccountForm(instance=user) + password_form = forms.PasswordChangeForm(user=user, request=request) send_reader_notifications = False next_url = request.GET.get("next", "") @@ -590,32 +591,18 @@ def edit_profile(request): ) elif "change_password" in request.POST: - old_password = request.POST.get("current_password") - new_pass_one = request.POST.get("new_password_one") - new_pass_two = request.POST.get("new_password_two") - - if old_password and request.user.check_password(old_password): - if new_pass_one == new_pass_two: - problems = request.user.password_policy_check(request, new_pass_one) - if not problems: - request.user.set_password(new_pass_one) - request.user.save() - messages.add_message( - request, messages.SUCCESS, _("Password updated.") - ) - else: - [ - messages.add_message(request, messages.INFO, problem) - for problem in problems - ] - else: - messages.add_message( - request, messages.WARNING, _("Passwords do not match") - ) - + password_form = forms.PasswordChangeForm( + request.POST, user=request.user, request=request + ) + if password_form.is_valid(): + password_form.save() + messages.add_message(request, messages.SUCCESS, _("Password updated.")) + return redirect(reverse("core_edit_profile")) else: messages.add_message( - request, messages.WARNING, _("Old password is not correct.") + request, + messages.WARNING, + _("Password not updated. Please correct the errors below."), ) elif "subscribe" in request.POST and send_reader_notifications: @@ -669,6 +656,7 @@ def edit_profile(request): template = "admin/core/accounts/edit_profile.html" context = { "form": form, + "password_form": password_form, "staff_group_membership_form": staff_group_membership_form, "user_to_edit": user, "send_reader_notifications": send_reader_notifications, diff --git a/src/templates/admin/core/accounts/edit_profile.html b/src/templates/admin/core/accounts/edit_profile.html index 61711894cd..74c8323491 100644 --- a/src/templates/admin/core/accounts/edit_profile.html +++ b/src/templates/admin/core/accounts/edit_profile.html @@ -83,30 +83,17 @@

{% trans "Update Password" %}

You can update your password by entering your existing password plus your new password. {% endblocktrans %}

+ {% trans "Password Requirements" %} + + {% include "admin/elements/forms/errors.html" with form=password_form %}
{% csrf_token %}
-
- - -
-
- - -
-
- - -
+ {% include "admin/elements/forms/field.html" with field=password_form.old_password %} + {% include "admin/elements/forms/field.html" with field=password_form.new_password_one %} + {% include "admin/elements/forms/field.html" with field=password_form.new_password_two %}