diff --git a/wagtail/admin/tests/viewsets/test_model_viewset.py b/wagtail/admin/tests/viewsets/test_model_viewset.py index 73e8b93630..66a64ae9e9 100644 --- a/wagtail/admin/tests/viewsets/test_model_viewset.py +++ b/wagtail/admin/tests/viewsets/test_model_viewset.py @@ -718,3 +718,28 @@ class TestBreadcrumbs(WagtailTestUtils, TestCase): breadcrumbs = soup.select_one('[data-controller="w-breadcrumbs"]') # Delete view shouldn't render breadcrumbs self.assertIsNone(breadcrumbs) + + +class TestLegacyPatterns(WagtailTestUtils, TestCase): + def setUp(self): + self.user = self.login() + + @classmethod + def setUpTestData(cls): + cls.object = JSONStreamModel.objects.create( + body='[{"type": "text", "value": "foo"}]', + ) + + def test_legacy_edit(self): + edit_url = reverse("streammodel:edit", args=(quote(self.object.pk),)) + legacy_edit_url = "/admin/streammodel/1/" + response = self.client.get(legacy_edit_url) + self.assertEqual(edit_url, "/admin/streammodel/edit/1/") + self.assertRedirects(response, edit_url, 301) + + def test_legacy_delete(self): + delete_url = reverse("streammodel:delete", args=(quote(self.object.pk),)) + legacy_delete_url = "/admin/streammodel/1/delete/" + response = self.client.get(legacy_delete_url) + self.assertEqual(delete_url, "/admin/streammodel/delete/1/") + self.assertRedirects(response, delete_url, 301) diff --git a/wagtail/admin/viewsets/model.py b/wagtail/admin/viewsets/model.py index b3fd8eee88..0bf18d004a 100644 --- a/wagtail/admin/viewsets/model.py +++ b/wagtail/admin/viewsets/model.py @@ -1,5 +1,6 @@ from django.core.exceptions import ImproperlyConfigured from django.forms.models import modelform_factory +from django.shortcuts import redirect from django.urls import path from django.utils.functional import cached_property @@ -151,6 +152,20 @@ class ModelViewSet(ViewSet): self.delete_view_class, **self.get_delete_view_kwargs() ) + @property + def redirect_to_edit_view(self): + def redirect_to_edit(request, pk): + return redirect(self.get_url_name("edit"), pk, permanent=True) + + return redirect_to_edit + + @property + def redirect_to_delete_view(self): + def redirect_to_delete(request, pk): + return redirect(self.get_url_name("delete"), pk, permanent=True) + + return redirect_to_delete + def get_templates(self, name="index", fallback=""): """ Utility function that provides a list of templates to try for a given @@ -415,6 +430,13 @@ class ModelViewSet(ViewSet): path("new/", self.add_view, name="add"), path("edit//", self.edit_view, name="edit"), path("delete//", self.delete_view, name="delete"), + ] + self._legacy_urlpatterns + + @cached_property + def _legacy_urlpatterns(self): + return [ + path("/", self.redirect_to_edit_view), + path("/delete/", self.redirect_to_delete_view), ] def on_register(self): diff --git a/wagtail/snippets/views/snippets.py b/wagtail/snippets/views/snippets.py index 90ad34cc4d..df04b2c358 100644 --- a/wagtail/snippets/views/snippets.py +++ b/wagtail/snippets/views/snippets.py @@ -977,20 +977,6 @@ class SnippetViewSet(ModelViewSet): workflow_history_url_name=self.get_url_name("workflow_history"), ) - @property - def redirect_to_edit_view(self): - def redirect_to_edit(request, pk): - return redirect(self.get_url_name("edit"), pk, permanent=True) - - return redirect_to_edit - - @property - def redirect_to_delete_view(self): - def redirect_to_delete(request, pk): - return redirect(self.get_url_name("delete"), pk, permanent=True) - - return redirect_to_delete - @property def redirect_to_usage_view(self): def redirect_to_usage(request, pk): @@ -1357,7 +1343,11 @@ class SnippetViewSet(ModelViewSet): ), ] - legacy_redirects = [ + return urlpatterns + self._legacy_urlpatterns + + @cached_property + def _legacy_urlpatterns(self): + return [ # legacy URLs that could potentially collide if the pk matches one of the reserved names above # ('add', 'edit' etc) - redirect to the unambiguous version path("/", self.redirect_to_edit_view), @@ -1365,8 +1355,6 @@ class SnippetViewSet(ModelViewSet): path("/usage/", self.redirect_to_usage_view), ] - return urlpatterns + legacy_redirects - def get_edit_handler(self): """ Returns the appropriate edit handler for this ``SnippetViewSet`` class.