diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5f4d7c7..f8433e0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,20 +9,19 @@ updates: ignore: - dependency-name: flake8 versions: - - 3.8.4 - - 3.9.0 + - 7.3.0 - dependency-name: coverage versions: - - "5.4" + - "7.13.4" - dependency-name: pytest versions: - - 6.2.2 + - 9.0.2 - dependency-name: isort versions: - - 5.7.0 + - 8.0.1 - dependency-name: django-debug-toolbar versions: - - "3.2" + - "6.2.0" - dependency-name: pytest-django versions: - - 4.1.0 + - 4.12.0 diff --git a/CHANGES b/CHANGES index 7dc216c..fe48d46 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +Unreleased +================== + - Add testing for Python 3.14, Wagtail 7.2, and Wagtail 7.3 + - Update dependencies to latest versions + + 1.8.0 (2026-02-05) ================== - bump required version of django-otp and update middleware diff --git a/sandbox/requirements.txt b/sandbox/requirements.txt index aebb00e..010059c 100644 --- a/sandbox/requirements.txt +++ b/sandbox/requirements.txt @@ -1,4 +1,4 @@ -Django>=3.2 -wagtail>=4.1 -django-debug-toolbar==3.2.2 +Django>=5.2 +Wagtail>=7.0 +django-debug-toolbar==6.2.0 -e .[docs,test] diff --git a/sandbox/sandbox/settings.py b/sandbox/sandbox/settings.py index 5ce9f87..8289b02 100644 --- a/sandbox/sandbox/settings.py +++ b/sandbox/sandbox/settings.py @@ -119,7 +119,6 @@ USE_I18N = True -USE_L10N = True USE_TZ = True diff --git a/sandbox/sandbox/urls.py b/sandbox/sandbox/urls.py index 7439f5a..8553305 100644 --- a/sandbox/sandbox/urls.py +++ b/sandbox/sandbox/urls.py @@ -1,6 +1,7 @@ import debug_toolbar from django.conf import settings from django.contrib import admin +from django.urls import path from django.urls import include, re_path from wagtail import urls as wagtail_urls @@ -9,9 +10,9 @@ urlpatterns = [ re_path(r'^admin/', admin.site.urls), - re_path(r'^cms/', include(wagtailadmin_urls)), - re_path(r'^documents/', include(wagtaildocs_urls)), - re_path(r'', include(wagtail_urls)), + path('cms/', include(wagtailadmin_urls)), + path('documents/', include(wagtaildocs_urls)), + path('', include(wagtail_urls)), ] @@ -24,5 +25,5 @@ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns = [ - re_path(r'^__debug__/', include(debug_toolbar.urls)), + path('__debug__/', include(debug_toolbar.urls)), ] + urlpatterns diff --git a/setup.py b/setup.py index 37b8836..292bb94 100644 --- a/setup.py +++ b/setup.py @@ -57,19 +57,16 @@ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Django", - "Framework :: Django :: 3.2", - "Framework :: Django :: 4.1", - "Framework :: Django :: 4.2", + "Framework :: Django :: 5.2", "Framework :: Wagtail", - "Framework :: Wagtail :: 2", - "Framework :: Wagtail :: 3", - "Framework :: Wagtail :: 4", + "Framework :: Wagtail :: 7", "License :: OSI Approved :: MIT License", "Programming Language :: Python", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ], zip_safe=False, ) diff --git a/src/wagtail_2fa/middleware.py b/src/wagtail_2fa/middleware.py index 9773a78..f506190 100644 --- a/src/wagtail_2fa/middleware.py +++ b/src/wagtail_2fa/middleware.py @@ -17,6 +17,10 @@ class VerifyUserMiddleware(_OTPMiddleware): "wagtailadmin_sprite", ] + def get_allowed_url_names(self): + extra = getattr(settings, "WAGTAIL_2FA_ALLOWED_URL_NAMES", []) + return self._allowed_url_names + list(extra) + # These URLs do not require verification if the user has no devices _allowed_url_names_no_device = [ "wagtail_2fa_device_list", @@ -75,7 +79,7 @@ def _require_verified_user(self, request): # Don't require verification for specified URL names request_url_name = resolve(request.path_info).url_name - if request_url_name in self._allowed_url_names: + if request_url_name in self.get_allowed_url_names(): return False # If the user does not have a device, don't require verification diff --git a/src/wagtail_2fa/templates/wagtail_2fa/device_list.html b/src/wagtail_2fa/templates/wagtail_2fa/device_list.html index 918812e..ada83a0 100644 --- a/src/wagtail_2fa/templates/wagtail_2fa/device_list.html +++ b/src/wagtail_2fa/templates/wagtail_2fa/device_list.html @@ -46,7 +46,10 @@

{# Users can only add devices to their own account #} {% if user_id == request.user.id %} - {% trans 'New device' %} + + + {% trans 'New device' %} + {% endif %} {% endblock %} diff --git a/src/wagtail_2fa/templates/wagtail_2fa/legacy/otp_form.html b/src/wagtail_2fa/templates/wagtail_2fa/legacy/otp_form.html deleted file mode 100644 index 05b3dd1..0000000 --- a/src/wagtail_2fa/templates/wagtail_2fa/legacy/otp_form.html +++ /dev/null @@ -1,62 +0,0 @@ -{% extends "wagtailadmin/admin_base.html" %} -{% load i18n wagtailadmin_tags %} -{% block titletag %}{% trans "Sign in" %}{% endblock %} -{% block bodyclass %}login{% endblock %} - -{% block furniture %} -
-

{% block branding_login %}{% trans "Enter your two-factor authentication code" %}{% endblock %}

- -
- {# Always show messages div so it can be appended to by JS #} - {% if messages or form.errors %} -
    - {% if form.errors %} -
  • {% blocktrans %}Invalid code{% endblocktrans %}
  • - {% endif %} - {% for message in messages %} -
  • {{ message }}
  • - {% endfor %} -
- {% endif %} -
- - {% block above_login %}{% endblock %} - -
- {% block login_form %} - {% csrf_token %} - - {% url 'wagtailadmin_home' as home_url %} - - - {% block fields %} - {% field field=form.otp_token %}{% endfield %} - - {% block extra_fields %} - {% for field_name, field in form.extra_fields %} - {% field field=field %}{% endfield %} - {% endfor %} - {% endblock extra_fields %} - - {% endblock %} - {% endblock %} -
- {% block submit_buttons %} - - - {% trans 'Sign out' %} - - {% endblock %} -
-
- - {% block below_login %}{% endblock %} - - {% block branding_logo %} - - {% endblock %} -
-{% endblock %} diff --git a/src/wagtail_2fa/templates/wagtail_2fa/otp_form.html b/src/wagtail_2fa/templates/wagtail_2fa/otp_form.html index 4186232..1cd69da 100644 --- a/src/wagtail_2fa/templates/wagtail_2fa/otp_form.html +++ b/src/wagtail_2fa/templates/wagtail_2fa/otp_form.html @@ -1,4 +1,4 @@ -{% extends "wagtailadmin/admin_base.html" %} +{% extends "wagtailadmin/base.html" %} {% load i18n wagtailadmin_tags %} {% block titletag %}{% trans "Sign in" %}{% endblock %} {% block bodyclass %}login{% endblock %} @@ -31,11 +31,11 @@

{% block branding_login %}{% trans "Enter your two-factor authentication cod {% block fields %} - {% field field=form.otp_token %}{% endfield %} + {% formattedfield form.otp_token %} {% block extra_fields %} {% for field_name, field in form.extra_fields %} - {% field field=field %}{% endfield %} + {% formattedfield field %} {% endfor %} {% endblock extra_fields %} @@ -45,7 +45,9 @@

{% block branding_login %}{% trans "Enter your two-factor authentication cod {% block submit_buttons %} - {% trans 'Sign out' %} + {% endblock %} diff --git a/src/wagtail_2fa/templates/wagtail_2fa/otp_form_v6.html b/src/wagtail_2fa/templates/wagtail_2fa/otp_form_v6.html deleted file mode 100644 index d114d95..0000000 --- a/src/wagtail_2fa/templates/wagtail_2fa/otp_form_v6.html +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "wagtailadmin/base.html" %} -{% load i18n wagtailadmin_tags %} -{% block titletag %}{% trans "Sign in" %}{% endblock %} -{% block bodyclass %}login{% endblock %} - -{% block furniture %} -
-

{% block branding_login %}{% trans "Enter your two-factor authentication code" %}{% endblock %}

- -
- {# Always show messages div so it can be appended to by JS #} - {% if messages or form.errors %} -
    - {% if form.errors %} -
  • {% blocktrans %}Invalid code{% endblocktrans %}
  • - {% endif %} - {% for message in messages %} -
  • {{ message }}
  • - {% endfor %} -
- {% endif %} -
- - {% block above_login %}{% endblock %} - -
- {% block login_form %} - {% csrf_token %} - - {% url 'wagtailadmin_home' as home_url %} - - - {% block fields %} - {% formattedfield field=form.otp_token %} - {% block extra_fields %} - {% for field_name, field in form.extra_fields %} - {% formattedfield field=field %} - {% endfor %} - {% endblock extra_fields %} - {% endblock %} - {% endblock %} -
- {% block submit_buttons %} - - - - - - {% endblock %} -
-
- - {% block below_login %}{% endblock %} - - {% block branding_logo %} - - {% endblock %} - - -
-{% endblock %} \ No newline at end of file diff --git a/src/wagtail_2fa/views.py b/src/wagtail_2fa/views.py index ef0b348..e59db1b 100644 --- a/src/wagtail_2fa/views.py +++ b/src/wagtail_2fa/views.py @@ -30,14 +30,7 @@ class LoginView(RedirectURLMixin, FormView): - - if WAGTAIL_VERSION >= (6, 0): - template_name = "wagtail_2fa/otp_form_v6.html" - elif WAGTAIL_VERSION < (6, 0) and WAGTAIL_VERSION >= (5, 0): - template_name = "wagtail_2fa/otp_form.html" - else: - template_name = "wagtail_2fa/legacy/otp_form.html" - + template_name = "wagtail_2fa/otp_form.html" form_class = forms.TokenForm redirect_field_name = REDIRECT_FIELD_NAME diff --git a/src/wagtail_2fa/wagtail_hooks.py b/src/wagtail_2fa/wagtail_hooks.py index 17284cf..9401ccc 100644 --- a/src/wagtail_2fa/wagtail_hooks.py +++ b/src/wagtail_2fa/wagtail_hooks.py @@ -1,23 +1,26 @@ from django.conf import settings from django.contrib.auth.models import Permission -from django.urls import path, re_path, reverse +from django.urls import path, reverse from django.utils.translation import gettext_lazy as _ -from wagtail import hooks +from wagtail import hooks, VERSION as WAGTAIL_VERSION from wagtail.admin.menu import MenuItem -from wagtail.users.widgets import UserListingButton -from wagtail_2fa import views +if WAGTAIL_VERSION >= (7, 1): + from wagtail.admin.widgets import Button +else: + from wagtail.users.widgets import UserListingButton as Button + -from wagtail import VERSION as WAGTAIL_VERSION +from wagtail_2fa import views @hooks.register("register_admin_urls") def urlpatterns(): return [ path("2fa/auth", views.LoginView.as_view(), name="wagtail_2fa_auth"), - re_path( - r"^2fa/devices/(?P\d+)$", + path( + "2fa/devices/", views.DeviceListView.as_view(), name="wagtail_2fa_device_list", ), @@ -26,18 +29,18 @@ def urlpatterns(): views.DeviceCreateView.as_view(), name="wagtail_2fa_device_new", ), - re_path( - r"^2fa/devices/(?P\d+)/update$", + path( + "2fa/devices//update", views.DeviceUpdateView.as_view(), name="wagtail_2fa_device_update", ), - re_path( - r"^2fa/devices/(?P\d+)/remove$", + path( + "2fa/devices//remove", views.DeviceDeleteView.as_view(), name="wagtail_2fa_device_remove", ), - re_path( - r"^2fa/devices/qr-code$", + path( + "2fa/devices/qr-code", views.DeviceQRCodeView.as_view(), name="wagtail_2fa_device_qrcode", ), @@ -70,25 +73,14 @@ def register(request): } -if WAGTAIL_VERSION >= (6, 0): - @hooks.register("register_user_listing_buttons") - def register_user_listing_buttons(user, request_user): - yield UserListingButton( - _("Manage 2FA"), - reverse("wagtail_2fa_device_list", kwargs={"user_id": user.id}), - attrs={"title": _("Edit this user")}, - priority=100, - ) -else: - @hooks.register("register_user_listing_buttons") - def register_user_listing_buttons(context, user): - yield UserListingButton( - _("Manage 2FA"), - reverse("wagtail_2fa_device_list", kwargs={"user_id": user.id}), - attrs={"title": _("Edit this user")}, - priority=100, - ) - +@hooks.register("register_user_listing_buttons") +def register_user_listing_buttons(user, request_user): + yield Button( + _("Manage 2FA"), + reverse("wagtail_2fa_device_list", kwargs={"user_id": user.id}), + attrs={"title": _("Edit this user")}, + priority=100, + ) @hooks.register("register_permissions") diff --git a/tox.ini b/tox.ini index 53f6768..94ae607 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] envlist = - python{3.13,3.14}-django{5.2}-wagtail{7.0} + python{3.13}-django{5.2}-wagtail{7.0,7.1,7.2,7.3}, + python{3.14}-django{5.2}-wagtail{7.2,7.3}, [gh-actions] python = @@ -17,6 +18,9 @@ basepython = deps = django5.2: Django>=5.2,<6.0 wagtail7.0: wagtail>=7.0,<7.1 + wagtail7.1: wagtail>=7.1,<7.2 + wagtail7.2: wagtail>=7.2,<7.3 + wagtail7.3: wagtail>=7.3,<7.4 extras = test