Make password reset form customisable

- Use a setting called WAGTAILADMIN_USER_PASSWORD_RESET_FORM to allow
users to specify a custom form for use in PasswordResetView

- Add an extra_fields property so that fields other than the
mandatory email field can be easily rendered in the template.

- Add extra blocks to the default template to allow users to
easily add their own stuff.

- Render extra fields in the template like we're doing in the
login template.
pull/8640/head
Josh Michael Karamuth 2022-05-23 13:46:01 +04:00 zatwierdzone przez LB (Ben Johnston)
rodzic daa47baddd
commit 3374ccee5e
8 zmienionych plików z 79 dodań i 4 usunięć

Wyświetl plik

@ -51,6 +51,7 @@ Changelog
* Remove legacy (non-next) breadcrumbs no longer used, remove `ModelAdmin` usage of breadcrumbs completely (Paarth Agarwal)
* Replace human-readable-date hover pattern with accessible tooltip variant across all of admin (Bernd de Ridder)
* Add legacy and new status tags to the pattern library (Steven Steinwand)
* Added `WAGTAILADMIN_USER_PASSWORD_RESET_FORM` setting for overriding the admin password reset form (Michael Karamuth)
* Fix: Typo in `ResumeWorkflowActionFormatter` message (Stefan Hammer)
* Fix: Throw a meaningful error when saving an image to an unrecognised image format (Christian Franke)
* Fix: Remove extra padding for headers with breadcrumbs on mobile viewport (Steven Steinwand)

Wyświetl plik

@ -214,6 +214,14 @@ This setting lets you change the number of items shown at 'Your most recent edit
Allows the default ``LoginForm`` to be extended with extra fields.
``WAGTAILADMIN_USER_PASSWORD_RESET_FORM``
-----------------------------------------
.. code-block:: python
WAGTAILADMIN_USER_PASSWORD_RESET_FORM = 'users.forms.PasswordResetForm'
Allows the default ``PasswordResetForm`` to be extended with extra fields.
.. _wagtail_gravatar_provider_url:

Wyświetl plik

@ -58,6 +58,7 @@ When using a queryset to render a list of images, you can now use the `prefetch_
* Remove legacy (non-next) breadcrumbs no longer used, remove `ModelAdmin` usage of breadcrumbs completely (Paarth Agarwal)
* Replace human-readable-date hover pattern with accessible tooltip variant across all of admin (Bernd de Ridder)
* Add legacy and new status tags to the pattern library (Steven Steinwand)
* Added `WAGTAILADMIN_USER_PASSWORD_RESET_FORM` setting for overriding the admin password reset form (Michael Karamuth)
### Bug fixes

Wyświetl plik

@ -38,6 +38,12 @@ class PasswordResetForm(DjangoPasswordResetForm):
required=True,
)
@property
def extra_fields(self):
for field_name in self.fields.keys():
if field_name not in ["email"]:
yield field_name, self[field_name]
class PasswordChangeForm(DjangoPasswordChangeForm):
"""

Wyświetl plik

@ -7,6 +7,8 @@
<main class="content-wrapper">
{% include "wagtailadmin/shared/non_field_errors.html" %}
{% block above_form %}{% endblock %}
<form method="post" novalidate>
{% csrf_token %}
<h1>{% trans "Reset your password" %}</h1>
@ -25,8 +27,22 @@
</div>
</div>
</li>
{% block extra_fields %}
{% for field_name, field in form.extra_fields %}
<li class="full">
{{ field.label_tag }}
<div class="field iconfield">
{{ field }}
</div>
</li>
{% endfor %}
{% endblock extra_fields %}
<li class="submit">
<button type="submit" class="button">{% trans 'Reset password' %}</button>
{% block submit_buttons %}
<button type="submit" class="button">{% trans 'Reset password' %}</button>
{% endblock %}
</li>
</ul>
</form>

Wyświetl plik

@ -1,14 +1,24 @@
from django.forms.fields import CharField
from django.test import TestCase
from django.test import SimpleTestCase, TestCase
from wagtail.admin.forms.auth import LoginForm
from wagtail.admin.forms.auth import LoginForm, PasswordResetForm
class CustomLoginForm(LoginForm):
captcha = CharField(label="Captcha", help_text="should be in extra_fields()")
class CustomPasswordResetForm(PasswordResetForm):
captcha = CharField(label="Captcha", help_text="should be in extra_fields()")
class TestLoginForm(TestCase):
def test_extra_fields(self):
form = CustomLoginForm()
self.assertEqual(list(form.extra_fields), [("captcha", form["captcha"])])
class TestPasswordResetForm(SimpleTestCase):
def test_extra_fields(self):
form = CustomPasswordResetForm()
self.assertEqual(list(form.extra_fields), [("captcha", form["captcha"])])

Wyświetl plik

@ -1,6 +1,8 @@
from django.test import TestCase, override_settings
from django.urls import reverse
from wagtail.admin.forms.auth import PasswordResetForm
from wagtail.admin.tests.test_forms import CustomPasswordResetForm
from wagtail.models import Page
from wagtail.test.utils import WagtailTestUtils
@ -101,3 +103,24 @@ class TestLoginView(TestCase, WagtailTestUtils):
)
self.assertFalse(self.client.session.get_expire_at_browser_close())
self.assertEqual(self.client.session.get_expiry_age(), 7)
class TestPasswordResetView(TestCase):
def test_password_reset_view_uses_correct_form(self):
response = self.client.get(reverse("wagtailadmin_password_reset"))
self.assertIsInstance(response.context.get("form"), PasswordResetForm)
with override_settings(
WAGTAILADMIN_USER_PASSWORD_RESET_FORM="wagtail.admin.tests.test_forms.CustomPasswordResetForm"
):
response = self.client.get(reverse("wagtailadmin_password_reset"))
self.assertIsInstance(response.context.get("form"), CustomPasswordResetForm)
@override_settings(
WAGTAILADMIN_USER_PASSWORD_RESET_FORM="wagtail.admin.tests.test_forms.CustomPasswordResetForm"
)
def test_password_reset_page_renders_extra_fields(self):
response = self.client.get(reverse("wagtailadmin_password_reset"))
self.assertContains(
response, '<input type="text" name="captcha" required id="id_captcha">'
)

Wyświetl plik

@ -41,6 +41,14 @@ def get_user_login_form():
return LoginForm
def get_password_reset_form():
form_setting = "WAGTAILADMIN_USER_PASSWORD_RESET_FORM"
if hasattr(settings, form_setting):
return get_custom_form(form_setting)
else:
return PasswordResetForm
# Helper functions to check password management settings to enable/disable views as appropriate.
# These are functions rather than class-level constants so that they can be overridden in tests
# by override_settings
@ -305,9 +313,11 @@ class PasswordResetView(PasswordResetEnabledViewMixin, auth_views.PasswordResetV
template_name = "wagtailadmin/account/password_reset/form.html"
email_template_name = "wagtailadmin/account/password_reset/email.txt"
subject_template_name = "wagtailadmin/account/password_reset/email_subject.txt"
form_class = PasswordResetForm
success_url = reverse_lazy("wagtailadmin_password_reset_done")
def get_form_class(self):
return get_password_reset_form()
class PasswordResetDoneView(
PasswordResetEnabledViewMixin, auth_views.PasswordResetDoneView