Pārlūkot izejas kodu

Ensure for_user is consistently passed to WagtailAdminModelForm (#9238)

Fixes #9230. When instantiating forms returned from `wagtail.admin.panels.get_form_for_model` (which are assumed to be WagtailAdminModelForm subclasses), always pass the for_user argument so that the form can incorporate custom logic that's dependent on the user object. Previously this was done for the main create/edit views, but not previews or revert.
Matt Westcott 2 gadi atpakaļ
vecāks
revīzija
82119360ac

+ 1 - 0
CHANGELOG.txt

@@ -39,6 +39,7 @@ Changelog
  * Fix: Add missing translated values to site settings' headers plus models presented in listings and audit report filtering labels (Stefan Hammer)
  * Fix: Remove `capitalize()` calls to avoid issues with other languages or incorrectly presented model names for reporting and parts of site settings (Stefan Hammer)
  * Fix: Add back rendering of `help_text` for InlinePanel (Matt Westcott)
+ * Fix: Ensure `for_user` argument is passed to the form class when previewing pages (Matt Westcott)
 
 4.0.3 (xx.xx.xxxx) - IN DEVELOPMENT
 ~~~~~~~~~~~~~~~~~~

+ 1 - 0
docs/releases/4.1.md

@@ -57,6 +57,7 @@ The `register_snippet` function now accepts a `SnippetViewSet` class, allowing v
  * Add missing translated values to site settings' headers plus models presented in listings and audit report filtering labels (Stefan Hammer)
  * Remove `capitalize()` calls to avoid issues with other languages or incorrectly presented model names for reporting and parts of site settings (Stefan Hammer)
  * Add back rendering of `help_text` for InlinePanel (Matt Westcott)
+ * Ensure `for_user` argument is passed to the form class when previewing pages (Matt Westcott)
 
 ## Upgrade considerations
 

+ 87 - 0
wagtail/admin/tests/pages/test_create_page.py

@@ -733,6 +733,47 @@ class TestPageCreation(TestCase, WagtailTestUtils):
         )
         self.assertEqual(response.status_code, 404)
 
+    def test_custom_validation(self):
+        response = self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "validatedpage", self.root_page.id),
+            ),
+            {
+                "title": "New page!",
+                "foo": "not bar",
+                "slug": "hello-world",
+            },
+        )
+
+        self.assertEqual(response.status_code, 200)
+        self.assertFormError(response, "form", "foo", "Field foo must be bar")
+        self.assertFalse(
+            Page.objects.filter(
+                path__startswith=self.root_page.path, slug="hello-world"
+            ).exists()
+        )
+
+        response = self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "validatedpage", self.root_page.id),
+            ),
+            {
+                "title": "New page!",
+                "foo": "superbar",
+                "slug": "hello-world",
+            },
+        )
+
+        page = Page.objects.get(
+            path__startswith=self.root_page.path, slug="hello-world"
+        )
+        # Should be redirected to edit page
+        self.assertRedirects(
+            response, reverse("wagtailadmin_pages:edit", args=(page.id,))
+        )
+
     def test_preview_on_create(self):
         post_data = {
             "title": "New page!",
@@ -765,6 +806,52 @@ class TestPageCreation(TestCase, WagtailTestUtils):
         self.assertTrue(response.context["self"].path.startswith(self.root_page.path))
         self.assertEqual(response.context["self"].get_parent(), self.root_page)
 
+    def test_preview_with_custom_validation(self):
+        post_data = {
+            "title": "New page!",
+            "foo": "not bar",
+            "slug": "hello-world",
+            "action-submit": "Submit",
+        }
+        preview_url = reverse(
+            "wagtailadmin_pages:preview_on_add",
+            args=("tests", "validatedpage", self.root_page.id),
+        )
+        response = self.client.post(preview_url, post_data)
+
+        # Check the JSON response
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"is_valid": False, "is_available": False},
+        )
+
+        post_data = {
+            "title": "New page!",
+            "foo": "superbar",
+            "slug": "hello-world",
+            "action-submit": "Submit",
+        }
+        preview_url = reverse(
+            "wagtailadmin_pages:preview_on_add",
+            args=("tests", "validatedpage", self.root_page.id),
+        )
+        response = self.client.post(preview_url, post_data)
+
+        # Check the JSON response
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"is_valid": True, "is_available": True},
+        )
+
+        response = self.client.get(preview_url)
+
+        # Check the HTML response
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "tests/validated_page.html")
+        self.assertContains(response, "foo = superbar")
+
     def test_whitespace_titles(self):
         post_data = {
             "title": " ",  # Single space on purpose

+ 2 - 2
wagtail/admin/views/generic/preview.py

@@ -58,9 +58,9 @@ class PreviewOnEdit(View):
 
         if not query_dict:
             # Query dict is empty, return null form
-            return form_class(instance=self.object)
+            return form_class(instance=self.object, for_user=self.request.user)
 
-        return form_class(query_dict, instance=self.object)
+        return form_class(query_dict, instance=self.object, for_user=self.request.user)
 
     def _get_data_from_session(self):
         post_data, _ = self.request.session.get(self.session_key, (None, None))

+ 11 - 2
wagtail/admin/views/pages/preview.py

@@ -37,9 +37,18 @@ class PreviewOnEdit(GenericPreviewOnEdit):
 
         if not query_dict:
             # Query dict is empty, return null form
-            return form_class(instance=self.object, parent_page=parent_page)
+            return form_class(
+                instance=self.object,
+                parent_page=parent_page,
+                for_user=self.request.user,
+            )
 
-        return form_class(query_dict, instance=self.object, parent_page=parent_page)
+        return form_class(
+            query_dict,
+            instance=self.object,
+            parent_page=parent_page,
+            for_user=self.request.user,
+        )
 
 
 class PreviewOnCreate(PreviewOnEdit):

+ 1 - 1
wagtail/admin/views/pages/revisions.py

@@ -38,7 +38,7 @@ def revisions_revert(request, page_id, revision_id):
     edit_handler = page_class.get_edit_handler()
     form_class = edit_handler.get_form_class()
 
-    form = form_class(instance=revision_page)
+    form = form_class(instance=revision_page, for_user=request.user)
     edit_handler = edit_handler.get_bound_panel(
         instance=revision_page, request=request, form=form
     )

+ 3 - 1
wagtail/test/testapp/forms.py

@@ -11,7 +11,9 @@ class ValidatedPageForm(WagtailAdminPageForm):
             return
 
         value = self.cleaned_data["foo"]
-        if value != "bar":
+        if self.for_user.is_superuser and value == "superbar":
+            pass
+        elif value != "bar":
             raise forms.ValidationError("Field foo must be bar")
         return value
 

+ 5 - 0
wagtail/test/testapp/templates/tests/validated_page.html

@@ -0,0 +1,5 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+    <h2>foo = {{ page.foo }}</h2>
+{% endblock %}