Allow page to change private page options

pull/12023/head
smark-1 2024-07-18 17:17:42 +01:00 zatwierdzone przez Jake Howard
rodzic 2d568dd825
commit 95eac5ab78
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 8198AEBFA7E86782
8 zmienionych plików z 129 dodań i 5 usunięć

Wyświetl plik

@ -24,6 +24,7 @@ Changelog
* Support customizations to `UserViewSet` via the app config (Sage Abdullah)
* Add word count and reading time metrics within the page editor (Albina Starykova. Sponsored by The Motley Fool)
* Implement a new design for accessibility checks (Albina Starykova)
* Allow changing available privacy options per page model (Shlomo Markowitz)
* Fix: Make `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` setting functional again (Rohit Sharma)
* Fix: Enable `richtext` template tag to convert lazy translation values (Benjamin Bach)
* Fix: Ensure permission labels on group permissions page are translated where available (Matt Westcott)

Wyświetl plik

@ -325,6 +325,33 @@ See also [django-treebeard](https://django-treebeard.readthedocs.io/en/latest/in
Controls the maximum number of pages of this type that can be created under any one parent page.
.. attribute:: private_page_options
Controls what privacy options are available for the page type.
The following options are available:
- ``'password'`` - Can restrict to use a shared password
- ``'groups'`` - Can restrict to users in specific groups
- ``'login'`` - Can restrict to logged in users
.. code-block:: python
class BreadPage(Page):
...
# default
private_page_options = ['password', 'groups', 'login']
# disable shared password
private_page_options = ['groups', 'login']
# only shared password
private_page_options = ['password']
# no privacy options for this page model
private_page_options = []
.. attribute:: exclude_fields_in_copy
An array of field names that will not be included when a Page is copied.

Wyświetl plik

@ -44,6 +44,7 @@ This feature was developed by Albina Starykova and sponsored by The Motley Fool.
* Make `routable_resolver_match` attribute available on RoutablePageMixin responses (Andy Chosak)
* Support customizations to `UserViewSet` via the app config (Sage Abdullah)
* Implement a new design for accessibility checks (Albina Starykova, sponsored by The Motley Fool)
* Allow changing available privacy options per page model (Shlomo Markowitz)
### Bug fixes

Wyświetl plik

@ -125,6 +125,9 @@ class CopyForm(forms.Form):
class PageViewRestrictionForm(BaseViewRestrictionForm):
def __init__(self, *args, **kwargs):
# get the list of private page options from the page
private_page_options = kwargs.pop("private_page_options", [])
super().__init__(*args, **kwargs)
if not getattr(settings, "WAGTAIL_PRIVATE_PAGE_OPTIONS", {}).get(
@ -136,6 +139,13 @@ class PageViewRestrictionForm(BaseViewRestrictionForm):
if choice[0] != PageViewRestriction.PASSWORD
]
del self.fields["password"]
# Remove the fields that are not allowed for the page
self.fields["restriction_type"].choices = [
choice
for choice in self.fields["restriction_type"].choices
if choice[0] in private_page_options
or choice[0] == PageViewRestriction.NONE
]
class Meta:
model = PageViewRestriction

Wyświetl plik

@ -0,0 +1,2 @@
{% load i18n %}
<p>{% trans "Changing the privacy for this page has been disabled." %}</p>

Wyświetl plik

@ -544,3 +544,68 @@ class TestPrivacyIndicators(WagtailTestUtils, TestCase):
self.assertContains(
response, '<div class="w-hidden" data-privacy-sidebar-public>'
)
def test_private_page_options_only_password_groups(self):
# change the private_page_options to password and login
original_private_page_options = self.public_page.private_page_options
self.public_page.specific.__class__.private_page_options = [
"password",
"groups",
]
response = self.client.get(
reverse("wagtailadmin_pages:set_privacy", args=(self.public_page.id,))
)
restriction_types = [
choice[0]
for choice in response.context["form"].fields["restriction_type"].choices
]
# Check response
self.assertListEqual(restriction_types, ["none", "password", "groups"])
# Reset the private_page_options to previous value
self.public_page.specific.__class__.private_page_options = (
original_private_page_options
)
def test_private_page_options_only_password_login(self):
# change the private_page_options to password and login
original_private_page_options = self.public_page.private_page_options
self.public_page.specific.__class__.private_page_options = ["password", "login"]
response = self.client.get(
reverse("wagtailadmin_pages:set_privacy", args=(self.public_page.id,))
)
restriction_types = [
choice[0]
for choice in response.context["form"].fields["restriction_type"].choices
]
# Check response
self.assertListEqual(restriction_types, ["none", "password", "login"])
# Reset the private_page_options to previous value
self.public_page.specific.__class__.private_page_options = (
original_private_page_options
)
def test_private_page_no_options(self):
# change the private_page_options to empty list
original_private_page_options = self.public_page.private_page_options
self.public_page.specific.__class__.private_page_options = []
response = self.client.get(
reverse("wagtailadmin_pages:set_privacy", args=(self.public_page.id,))
)
# Check response
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "wagtailadmin/page_privacy/no_privacy.html")
# Reset the private_page_options to previous value
self.public_page.specific.__class__.private_page_options = (
original_private_page_options
)

Wyświetl plik

@ -7,7 +7,7 @@ from wagtail.models import Page, PageViewRestriction
def set_privacy(request, page_id):
page = get_object_or_404(Page, id=page_id)
page = get_object_or_404(Page, id=page_id).specific_deferred
page_perms = page.permissions_for_user(request.user)
if not page_perms.can_set_view_restrictions():
raise PermissionDenied
@ -16,13 +16,17 @@ def set_privacy(request, page_id):
restrictions = page.get_view_restrictions().order_by("page__depth")
if restrictions:
restriction = restrictions[0]
restriction_exists_on_ancestor = restriction.page != page
restriction_exists_on_ancestor = restriction.page.id != page.id
else:
restriction = None
restriction_exists_on_ancestor = False
if request.method == "POST":
form = PageViewRestrictionForm(request.POST, instance=restriction)
form = PageViewRestrictionForm(
request.POST,
instance=restriction,
private_page_options=page.private_page_options,
)
if form.is_valid() and not restriction_exists_on_ancestor:
if form.cleaned_data["restriction_type"] == PageViewRestriction.NONE:
# remove any existing restriction
@ -49,10 +53,15 @@ def set_privacy(request, page_id):
else: # request is a GET
if not restriction_exists_on_ancestor:
if restriction:
form = PageViewRestrictionForm(instance=restriction)
form = PageViewRestrictionForm(
instance=restriction, private_page_options=page.private_page_options
)
else:
# no current view restrictions on this page
form = PageViewRestrictionForm(initial={"restriction_type": "none"})
form = PageViewRestrictionForm(
initial={"restriction_type": "none"},
private_page_options=page.private_page_options,
)
if restriction_exists_on_ancestor:
# display a message indicating that there is a restriction at ancestor level -
@ -65,6 +74,12 @@ def set_privacy(request, page_id):
"page_with_restriction": restriction.page,
},
)
elif len(page.private_page_options) == 0:
return render_modal_workflow(
request,
"wagtailadmin/page_privacy/no_privacy.html",
None,
)
else:
# no restriction set at ancestor level - can set restrictions here
return render_modal_workflow(

Wyświetl plik

@ -1291,6 +1291,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
promote_panels = []
settings_panels = []
# Privacy options for page
private_page_options = ["password", "groups", "login"]
@staticmethod
def route_for_request(request: "HttpRequest", path: str) -> RouteResult | None:
"""