From 8654aadb6380f2a86db04097a7bd08f6acb13817 Mon Sep 17 00:00:00 2001
From: smark-1 <75799735+smark-1@users.noreply.github.com>
Date: Mon, 2 Sep 2024 14:38:33 -0400
Subject: [PATCH] Add method to set a default privacy option on Page models

Fixes #3708
---
 wagtail/admin/tests/pages/test_create_page.py | 122 ++++++++++++++++++
 wagtail/admin/views/pages/create.py           |  48 ++++++-
 wagtail/models/pages.py                       |   4 +
 3 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/wagtail/admin/tests/pages/test_create_page.py b/wagtail/admin/tests/pages/test_create_page.py
index 6bf874e868..5d73077a9f 100644
--- a/wagtail/admin/tests/pages/test_create_page.py
+++ b/wagtail/admin/tests/pages/test_create_page.py
@@ -783,6 +783,128 @@ class TestPageCreation(WagtailTestUtils, TestCase):
         # form should be marked as having unsaved changes for the purposes of the dirty-forms warning
         self.assertContains(response, 'data-w-unsaved-force-value="true"')
 
+    def test_create_default_privacy_page_public(self):
+        post_data = {
+            "title": "New page!",
+            "content": "Some content",
+            "slug": "hello-world",
+            "action-publish": "Publish",
+        }
+
+        self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "simplepage", self.root_page.id),
+            ),
+            post_data,
+        )
+
+        # Find the page and check it
+        page = self.root_page.get_children().filter(slug="hello-world").first()
+
+        self.assertEqual(PageViewRestriction.objects.filter(page=page).count(), 0)
+
+    @mock.patch("wagtail.test.testapp.models.SimplePage.get_default_privacy_setting")
+    def test_create_default_privacy_page_logged_in(
+        self, mock_get_default_privacy_setting
+    ):
+        mock_get_default_privacy_setting.return_value = {"type": "login"}
+
+        post_data = {
+            "title": "New page!",
+            "content": "Some content",
+            "slug": "hello-world",
+            "action-publish": "Publish",
+        }
+
+        self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "simplepage", self.root_page.id),
+            ),
+            post_data,
+        )
+
+        # Find the page and check it
+        page = Page.objects.get(
+            path__startswith=self.root_page.path, slug="hello-world"
+        ).specific
+
+        self.assertEqual(
+            PageViewRestriction.objects.filter(
+                page=page, restriction_type="login"
+            ).count(),
+            1,
+        )
+
+    @mock.patch("wagtail.test.testapp.models.SimplePage.get_default_privacy_setting")
+    def test_create_default_privacy_page_shared_password(
+        self, mock_get_default_privacy_setting
+    ):
+        mock_get_default_privacy_setting.return_value = {
+            "type": "password",
+            "password": "password",
+        }
+        post_data = {
+            "title": "New page!",
+            "content": "Some content",
+            "slug": "hello-world",
+            "action-publish": "Publish",
+        }
+
+        self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "simplepage", self.root_page.id),
+            ),
+            post_data,
+        )
+
+        # Find the page and check it
+        page = Page.objects.get(
+            path__startswith=self.root_page.path, slug="hello-world"
+        ).specific
+
+        self.assertEqual(
+            PageViewRestriction.objects.filter(
+                page=page, restriction_type="password"
+            ).count(),
+            1,
+        )
+
+    @mock.patch("wagtail.test.testapp.models.SimplePage.get_default_privacy_setting")
+    def test_create_default_privacy_page_user_groups(
+        self, mock_get_default_privacy_setting
+    ):
+        mock_get_default_privacy_setting.return_value = {"type": "groups", "groups": []}
+
+        post_data = {
+            "title": "New page!",
+            "content": "Some content",
+            "slug": "hello-world",
+            "action-publish": "Publish",
+        }
+
+        self.client.post(
+            reverse(
+                "wagtailadmin_pages:add",
+                args=("tests", "simplepage", self.root_page.id),
+            ),
+            post_data,
+        )
+
+        # Find the page and check it
+        page = Page.objects.get(
+            path__startswith=self.root_page.path, slug="hello-world"
+        ).specific
+
+        self.assertEqual(
+            PageViewRestriction.objects.filter(
+                page=page, restriction_type="groups"
+            ).count(),
+            1,
+        )
+
     def test_create_nonexistantparent(self):
         response = self.client.get(
             reverse("wagtailadmin_pages:add", args=("tests", "simplepage", 100000))
diff --git a/wagtail/admin/views/pages/create.py b/wagtail/admin/views/pages/create.py
index c378ad1faa..8bbc99fe45 100644
--- a/wagtail/admin/views/pages/create.py
+++ b/wagtail/admin/views/pages/create.py
@@ -24,7 +24,13 @@ from wagtail.admin.ui.side_panels import (
 from wagtail.admin.utils import get_valid_next_url_from_request
 from wagtail.admin.views.generic import HookResponseMixin
 from wagtail.admin.views.generic.base import WagtailAdminTemplateMixin
-from wagtail.models import Locale, Page, PageSubscription
+from wagtail.models import (
+    BaseViewRestriction,
+    Locale,
+    Page,
+    PageSubscription,
+    PageViewRestriction,
+)
 
 
 def add_subpage(request, parent_page_id):
@@ -182,6 +188,37 @@ class CreateView(WagtailAdminTemplateMixin, HookResponseMixin, View):
     def get_view_live_message_button(self):
         return messages.button(self.page.url, _("View live"), new_window=False)
 
+    def set_default_privacy_setting(self):
+        # privacy setting options BaseViewRestriction.RESTRICTION_CHOICES
+        default_privacy_setting = self.page.get_default_privacy_setting(self.request)
+
+        if default_privacy_setting["type"] == BaseViewRestriction.NONE:
+            # default privacy setting is public no need to do anything
+            pass
+        elif default_privacy_setting["type"] == BaseViewRestriction.LOGIN:
+            PageViewRestriction.objects.create(
+                page=self.page,
+                restriction_type=BaseViewRestriction.LOGIN,
+            )
+        elif default_privacy_setting["type"] == BaseViewRestriction.PASSWORD:
+            PageViewRestriction.objects.create(
+                page=self.page,
+                restriction_type=BaseViewRestriction.PASSWORD,
+                password=default_privacy_setting["password"],
+            )
+        elif default_privacy_setting["type"] == BaseViewRestriction.GROUPS:
+            # Create a page view restriction for groups
+            groups_page_restriction = PageViewRestriction.objects.create(
+                page=self.page,
+                restriction_type=BaseViewRestriction.GROUPS,
+            )
+            # add groups to the page view restriction
+            groups_page_restriction.groups.set(default_privacy_setting["groups"])
+        else:
+            raise ValueError(
+                f"Invalid privacy setting {default_privacy_setting.get('type')!r}"
+            )
+
     def save_action(self):
         self.page = self.form.save(commit=False)
         self.page.live = False
@@ -189,6 +226,9 @@ class CreateView(WagtailAdminTemplateMixin, HookResponseMixin, View):
         # Save page
         self.parent_page.add_child(instance=self.page)
 
+        # Set page privacy setting
+        self.set_default_privacy_setting()
+
         # Save revision
         self.page.save_revision(user=self.request.user, log_action=True)
 
@@ -216,6 +256,9 @@ class CreateView(WagtailAdminTemplateMixin, HookResponseMixin, View):
         # Save page
         self.parent_page.add_child(instance=self.page)
 
+        # Set page privacy setting
+        self.set_default_privacy_setting()
+
         # Save revision
         revision = self.page.save_revision(user=self.request.user, log_action=True)
 
@@ -270,6 +313,9 @@ class CreateView(WagtailAdminTemplateMixin, HookResponseMixin, View):
         # Save page
         self.parent_page.add_child(instance=self.page)
 
+        # Set page privacy setting
+        self.set_default_privacy_setting()
+
         # Save revision
         self.page.save_revision(user=self.request.user, log_action=True)
 
diff --git a/wagtail/models/pages.py b/wagtail/models/pages.py
index 3d123a4cc5..efd938fb85 100644
--- a/wagtail/models/pages.py
+++ b/wagtail/models/pages.py
@@ -1429,6 +1429,10 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
         except self.specific_class.DoesNotExist:
             return None
 
+    def get_default_privacy_setting(self, request: HttpRequest):
+        """Set the default privacy setting for a page."""
+        return {"type": BaseViewRestriction.NONE}
+
     @classmethod
     def clean_subpage_models(cls):
         """