962 lines
42 KiB
Python
962 lines
42 KiB
Python
import json
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import Group
|
|
from django.test import Client, TestCase, override_settings
|
|
from django.utils import timezone
|
|
|
|
from wagtail.models import (
|
|
GroupApprovalTask,
|
|
GroupPagePermission,
|
|
Locale,
|
|
Page,
|
|
Workflow,
|
|
WorkflowTask,
|
|
)
|
|
from wagtail.permission_policies.pages import PagePermissionPolicy
|
|
from wagtail.test.testapp.models import (
|
|
BusinessSubIndex,
|
|
CustomPermissionPage,
|
|
CustomPermissionTester,
|
|
EventIndex,
|
|
EventPage,
|
|
SingletonPageViaMaxCount,
|
|
)
|
|
|
|
|
|
class TestPagePermission(TestCase):
|
|
fixtures = ["test.json"]
|
|
|
|
def create_workflow_and_task(self):
|
|
workflow = Workflow.objects.create(name="test_workflow")
|
|
task_1 = GroupApprovalTask.objects.create(name="test_task_1")
|
|
task_1.groups.add(Group.objects.get(name="Event moderators"))
|
|
WorkflowTask.objects.create(
|
|
workflow=workflow, task=task_1.task_ptr, sort_order=1
|
|
)
|
|
return workflow, task_1
|
|
|
|
def test_nonpublisher_page_permissions(self):
|
|
event_editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
board_meetings_page = BusinessSubIndex.objects.get(
|
|
url_path="/home/events/businessy-events/board-meetings/"
|
|
)
|
|
|
|
homepage_perms = homepage.permissions_for_user(event_editor)
|
|
christmas_page_perms = christmas_page.permissions_for_user(event_editor)
|
|
unpub_perms = unpublished_event_page.permissions_for_user(event_editor)
|
|
someone_elses_event_perms = someone_elses_event_page.permissions_for_user(
|
|
event_editor
|
|
)
|
|
board_meetings_perms = board_meetings_page.permissions_for_user(event_editor)
|
|
|
|
self.assertFalse(homepage_perms.can_add_subpage())
|
|
self.assertTrue(christmas_page_perms.can_add_subpage())
|
|
self.assertTrue(unpub_perms.can_add_subpage())
|
|
self.assertTrue(someone_elses_event_perms.can_add_subpage())
|
|
|
|
self.assertFalse(homepage_perms.can_edit())
|
|
self.assertTrue(christmas_page_perms.can_edit())
|
|
self.assertTrue(unpub_perms.can_edit())
|
|
# basic 'add' permission doesn't allow editing pages owned by someone else
|
|
self.assertFalse(someone_elses_event_perms.can_edit())
|
|
|
|
self.assertFalse(homepage_perms.can_delete())
|
|
self.assertFalse(
|
|
christmas_page_perms.can_delete()
|
|
) # cannot delete because it is published
|
|
self.assertTrue(unpub_perms.can_delete())
|
|
self.assertFalse(someone_elses_event_perms.can_delete())
|
|
|
|
self.assertFalse(homepage_perms.can_publish())
|
|
self.assertFalse(christmas_page_perms.can_publish())
|
|
self.assertFalse(unpub_perms.can_publish())
|
|
|
|
self.assertFalse(homepage_perms.can_unpublish())
|
|
self.assertFalse(christmas_page_perms.can_unpublish())
|
|
self.assertFalse(unpub_perms.can_unpublish())
|
|
|
|
self.assertFalse(homepage_perms.can_publish_subpage())
|
|
self.assertFalse(christmas_page_perms.can_publish_subpage())
|
|
self.assertFalse(unpub_perms.can_publish_subpage())
|
|
|
|
self.assertFalse(homepage_perms.can_reorder_children())
|
|
self.assertFalse(christmas_page_perms.can_reorder_children())
|
|
self.assertFalse(unpub_perms.can_reorder_children())
|
|
|
|
self.assertFalse(homepage_perms.can_move())
|
|
# cannot move because this would involve unpublishing from its current location
|
|
self.assertFalse(christmas_page_perms.can_move())
|
|
self.assertTrue(unpub_perms.can_move())
|
|
self.assertFalse(someone_elses_event_perms.can_move())
|
|
|
|
# cannot move because this would involve unpublishing from its current location
|
|
self.assertFalse(christmas_page_perms.can_move_to(unpublished_event_page))
|
|
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
|
self.assertFalse(
|
|
unpub_perms.can_move_to(homepage)
|
|
) # no permission to create pages at destination
|
|
self.assertFalse(
|
|
unpub_perms.can_move_to(unpublished_event_page)
|
|
) # cannot make page a child of itself
|
|
# cannot move because the subpage_types rule of BusinessSubIndex forbids EventPage as a subpage
|
|
self.assertFalse(unpub_perms.can_move_to(board_meetings_page))
|
|
|
|
self.assertTrue(board_meetings_perms.can_move())
|
|
# cannot move because the parent_page_types rule of BusinessSubIndex forbids EventPage as a parent
|
|
self.assertFalse(board_meetings_perms.can_move_to(christmas_page))
|
|
|
|
def test_publisher_page_permissions(self):
|
|
event_moderator = get_user_model().objects.get(
|
|
email="eventmoderator@example.com"
|
|
)
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
board_meetings_page = BusinessSubIndex.objects.get(
|
|
url_path="/home/events/businessy-events/board-meetings/"
|
|
)
|
|
|
|
homepage_perms = homepage.permissions_for_user(event_moderator)
|
|
christmas_page_perms = christmas_page.permissions_for_user(event_moderator)
|
|
unpub_perms = unpublished_event_page.permissions_for_user(event_moderator)
|
|
board_meetings_perms = board_meetings_page.permissions_for_user(event_moderator)
|
|
|
|
self.assertFalse(homepage_perms.can_add_subpage())
|
|
self.assertTrue(christmas_page_perms.can_add_subpage())
|
|
self.assertTrue(unpub_perms.can_add_subpage())
|
|
|
|
self.assertFalse(homepage_perms.can_edit())
|
|
self.assertTrue(christmas_page_perms.can_edit())
|
|
self.assertTrue(unpub_perms.can_edit())
|
|
|
|
self.assertFalse(homepage_perms.can_delete())
|
|
# can delete a published page because we have publish permission
|
|
self.assertTrue(christmas_page_perms.can_delete())
|
|
self.assertTrue(unpub_perms.can_delete())
|
|
|
|
self.assertFalse(homepage_perms.can_publish())
|
|
self.assertTrue(christmas_page_perms.can_publish())
|
|
self.assertTrue(unpub_perms.can_publish())
|
|
|
|
self.assertFalse(homepage_perms.can_unpublish())
|
|
self.assertTrue(christmas_page_perms.can_unpublish())
|
|
self.assertFalse(
|
|
unpub_perms.can_unpublish()
|
|
) # cannot unpublish a page that isn't published
|
|
|
|
self.assertFalse(homepage_perms.can_publish_subpage())
|
|
self.assertTrue(christmas_page_perms.can_publish_subpage())
|
|
self.assertTrue(unpub_perms.can_publish_subpage())
|
|
|
|
self.assertFalse(homepage_perms.can_reorder_children())
|
|
self.assertTrue(christmas_page_perms.can_reorder_children())
|
|
self.assertTrue(unpub_perms.can_reorder_children())
|
|
|
|
self.assertFalse(homepage_perms.can_move())
|
|
self.assertTrue(christmas_page_perms.can_move())
|
|
self.assertTrue(unpub_perms.can_move())
|
|
|
|
self.assertTrue(christmas_page_perms.can_move_to(unpublished_event_page))
|
|
self.assertTrue(unpub_perms.can_move_to(christmas_page))
|
|
self.assertFalse(
|
|
unpub_perms.can_move_to(homepage)
|
|
) # no permission to create pages at destination
|
|
self.assertFalse(
|
|
unpub_perms.can_move_to(unpublished_event_page)
|
|
) # cannot make page a child of itself
|
|
# cannot move because the subpage_types rule of BusinessSubIndex forbids EventPage as a subpage
|
|
self.assertFalse(unpub_perms.can_move_to(board_meetings_page))
|
|
|
|
self.assertTrue(board_meetings_perms.can_move())
|
|
# cannot move because the parent_page_types rule of BusinessSubIndex forbids EventPage as a parent
|
|
self.assertFalse(board_meetings_perms.can_move_to(christmas_page))
|
|
|
|
def test_publish_page_permissions_without_edit(self):
|
|
event_moderator = get_user_model().objects.get(
|
|
email="eventmoderator@example.com"
|
|
)
|
|
|
|
# Remove 'edit' permission from the event_moderator group
|
|
GroupPagePermission.objects.filter(
|
|
group__name="Event moderators", permission__codename="change_page"
|
|
).delete()
|
|
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
# 'someone else's event' is owned by eventmoderator
|
|
moderator_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
homepage_perms = homepage.permissions_for_user(event_moderator)
|
|
christmas_page_perms = christmas_page.permissions_for_user(event_moderator)
|
|
unpub_perms = unpublished_event_page.permissions_for_user(event_moderator)
|
|
moderator_event_perms = moderator_event_page.permissions_for_user(
|
|
event_moderator
|
|
)
|
|
|
|
# we still have add permission within events
|
|
self.assertFalse(homepage_perms.can_add_subpage())
|
|
self.assertTrue(christmas_page_perms.can_add_subpage())
|
|
|
|
# add permission lets us edit our own event
|
|
self.assertFalse(christmas_page_perms.can_edit())
|
|
self.assertTrue(moderator_event_perms.can_edit())
|
|
|
|
# with add + publish permissions, can delete a published page owned by us
|
|
self.assertTrue(moderator_event_perms.can_delete())
|
|
# but NOT a page owned by someone else (which would require edit permission)
|
|
self.assertFalse(christmas_page_perms.can_delete())
|
|
# ...even an unpublished one
|
|
self.assertFalse(unpub_perms.can_delete())
|
|
|
|
# we can still publish/unpublish events regardless of owner
|
|
self.assertFalse(homepage_perms.can_publish())
|
|
self.assertTrue(christmas_page_perms.can_publish())
|
|
self.assertTrue(unpub_perms.can_publish())
|
|
|
|
self.assertFalse(homepage_perms.can_unpublish())
|
|
self.assertTrue(christmas_page_perms.can_unpublish())
|
|
self.assertFalse(
|
|
unpub_perms.can_unpublish()
|
|
) # cannot unpublish a page that isn't published
|
|
|
|
self.assertFalse(homepage_perms.can_publish_subpage())
|
|
self.assertTrue(christmas_page_perms.can_publish_subpage())
|
|
self.assertTrue(unpub_perms.can_publish_subpage())
|
|
|
|
# reorder permission is considered equivalent to publish permission
|
|
# (so we can do it on pages we can't edit)
|
|
self.assertFalse(homepage_perms.can_reorder_children())
|
|
self.assertTrue(christmas_page_perms.can_reorder_children())
|
|
self.assertTrue(unpub_perms.can_reorder_children())
|
|
|
|
# moving requires edit permission
|
|
self.assertFalse(homepage_perms.can_move())
|
|
self.assertFalse(christmas_page_perms.can_move())
|
|
self.assertTrue(moderator_event_perms.can_move())
|
|
# and add permission on the destination
|
|
self.assertFalse(moderator_event_perms.can_move_to(homepage))
|
|
self.assertTrue(moderator_event_perms.can_move_to(unpublished_event_page))
|
|
|
|
def test_cannot_bulk_delete_without_permissions(self):
|
|
event_moderator = get_user_model().objects.get(
|
|
email="eventmoderator@example.com"
|
|
)
|
|
events_page = EventIndex.objects.get(url_path="/home/events/")
|
|
events_perms = events_page.permissions_for_user(event_moderator)
|
|
|
|
self.assertFalse(events_perms.can_delete())
|
|
|
|
def test_can_bulk_delete_with_permissions(self):
|
|
event_moderator = get_user_model().objects.get(
|
|
email="eventmoderator@example.com"
|
|
)
|
|
events_page = EventIndex.objects.get(url_path="/home/events/")
|
|
|
|
# Assign 'bulk_delete' permission to the event_moderator group
|
|
event_moderators_group = Group.objects.get(name="Event moderators")
|
|
GroupPagePermission.objects.create(
|
|
group=event_moderators_group,
|
|
page=events_page,
|
|
permission_type="bulk_delete",
|
|
)
|
|
|
|
events_perms = events_page.permissions_for_user(event_moderator)
|
|
|
|
self.assertTrue(events_perms.can_delete())
|
|
|
|
def test_need_delete_permission_to_bulk_delete(self):
|
|
"""
|
|
Having bulk_delete permission is not in itself sufficient to allow deleting pages -
|
|
you need actual edit permission on the pages too.
|
|
|
|
In this test the event editor is given bulk_delete permission, but since their
|
|
only other permission is 'add', they cannot delete published pages or pages owned
|
|
by other users, and therefore the bulk deletion cannot happen.
|
|
"""
|
|
event_editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
events_page = EventIndex.objects.get(url_path="/home/events/")
|
|
|
|
# Assign 'bulk_delete' permission to the event_editor group
|
|
event_editors_group = Group.objects.get(name="Event editors")
|
|
GroupPagePermission.objects.create(
|
|
group=event_editors_group, page=events_page, permission_type="bulk_delete"
|
|
)
|
|
|
|
events_perms = events_page.permissions_for_user(event_editor)
|
|
|
|
self.assertFalse(events_perms.can_delete())
|
|
|
|
def test_inactive_user_has_no_permissions(self):
|
|
user = get_user_model().objects.get(email="inactiveuser@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
|
|
christmas_page_perms = christmas_page.permissions_for_user(user)
|
|
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
|
|
|
self.assertFalse(unpub_perms.can_add_subpage())
|
|
self.assertFalse(unpub_perms.can_edit())
|
|
self.assertFalse(unpub_perms.can_delete())
|
|
self.assertFalse(unpub_perms.can_publish())
|
|
self.assertFalse(christmas_page_perms.can_unpublish())
|
|
self.assertFalse(unpub_perms.can_publish_subpage())
|
|
self.assertFalse(unpub_perms.can_reorder_children())
|
|
self.assertFalse(unpub_perms.can_move())
|
|
self.assertFalse(unpub_perms.can_move_to(christmas_page))
|
|
|
|
def test_superuser_has_full_permissions(self):
|
|
user = get_user_model().objects.get(email="superuser@example.com")
|
|
homepage = Page.objects.get(url_path="/home/").specific
|
|
root = Page.objects.get(url_path="/").specific
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
board_meetings_page = BusinessSubIndex.objects.get(
|
|
url_path="/home/events/businessy-events/board-meetings/"
|
|
)
|
|
|
|
homepage_perms = homepage.permissions_for_user(user)
|
|
root_perms = root.permissions_for_user(user)
|
|
unpub_perms = unpublished_event_page.permissions_for_user(user)
|
|
board_meetings_perms = board_meetings_page.permissions_for_user(user)
|
|
|
|
self.assertTrue(homepage_perms.can_add_subpage())
|
|
self.assertTrue(root_perms.can_add_subpage())
|
|
|
|
self.assertTrue(homepage_perms.can_edit())
|
|
self.assertFalse(
|
|
root_perms.can_edit()
|
|
) # root is not a real editable page, even to superusers
|
|
|
|
self.assertTrue(homepage_perms.can_delete())
|
|
self.assertFalse(root_perms.can_delete())
|
|
|
|
self.assertTrue(homepage_perms.can_publish())
|
|
self.assertFalse(root_perms.can_publish())
|
|
|
|
self.assertTrue(homepage_perms.can_unpublish())
|
|
self.assertFalse(root_perms.can_unpublish())
|
|
self.assertFalse(unpub_perms.can_unpublish())
|
|
|
|
self.assertTrue(homepage_perms.can_publish_subpage())
|
|
self.assertTrue(root_perms.can_publish_subpage())
|
|
|
|
self.assertTrue(homepage_perms.can_reorder_children())
|
|
self.assertTrue(root_perms.can_reorder_children())
|
|
|
|
self.assertTrue(homepage_perms.can_move())
|
|
self.assertFalse(root_perms.can_move())
|
|
|
|
self.assertTrue(homepage_perms.can_move_to(root))
|
|
self.assertFalse(homepage_perms.can_move_to(unpublished_event_page))
|
|
|
|
# cannot move because the subpage_types rule of BusinessSubIndex forbids EventPage as a subpage
|
|
self.assertFalse(unpub_perms.can_move_to(board_meetings_page))
|
|
self.assertTrue(board_meetings_perms.can_move())
|
|
# cannot move because the parent_page_types rule of BusinessSubIndex forbids EventPage as a parent
|
|
self.assertFalse(board_meetings_perms.can_move_to(unpublished_event_page))
|
|
|
|
def test_cant_move_pages_between_locales(self):
|
|
user = get_user_model().objects.get(email="superuser@example.com")
|
|
homepage = Page.objects.get(url_path="/home/").specific
|
|
root = Page.objects.get(url_path="/").specific
|
|
|
|
fr_locale = Locale.objects.create(language_code="fr")
|
|
fr_page = root.add_child(
|
|
instance=Page(
|
|
title="French page",
|
|
slug="french-page",
|
|
locale=fr_locale,
|
|
)
|
|
)
|
|
|
|
fr_homepage = root.add_child(
|
|
instance=Page(
|
|
title="French homepage",
|
|
slug="french-homepage",
|
|
locale=fr_locale,
|
|
)
|
|
)
|
|
|
|
french_page_perms = fr_page.permissions_for_user(user)
|
|
|
|
# fr_page can be moved into fr_homepage but not homepage
|
|
self.assertFalse(french_page_perms.can_move_to(homepage))
|
|
self.assertTrue(french_page_perms.can_move_to(fr_homepage))
|
|
|
|
# All pages can be moved to the root, regardless what language they are
|
|
self.assertTrue(french_page_perms.can_move_to(root))
|
|
|
|
events_index = Page.objects.get(url_path="/home/events/")
|
|
events_index_perms = events_index.permissions_for_user(user)
|
|
self.assertTrue(events_index_perms.can_move_to(root))
|
|
|
|
def test_editable_pages_for_user_with_add_permission(self):
|
|
event_editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
editable_pages = policy.instances_user_has_permission_for(
|
|
event_editor, "change"
|
|
)
|
|
can_edit_pages = policy.user_has_permission(event_editor, "change")
|
|
publishable_pages = policy.instances_user_has_permission_for(
|
|
event_editor, "publish"
|
|
)
|
|
can_publish_pages = policy.user_has_permission(event_editor, "publish")
|
|
|
|
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
|
|
|
self.assertTrue(can_edit_pages)
|
|
|
|
self.assertFalse(publishable_pages.filter(id=homepage.id).exists())
|
|
self.assertFalse(publishable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=unpublished_event_page.id).exists()
|
|
)
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
self.assertFalse(can_publish_pages)
|
|
|
|
def test_explorable_pages(self):
|
|
event_editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
about_us_page = Page.objects.get(url_path="/home/about-us/")
|
|
|
|
policy = PagePermissionPolicy()
|
|
explorable_pages = policy.explorable_instances(event_editor)
|
|
|
|
# Verify all pages below /home/events/ are explorable
|
|
self.assertTrue(explorable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(explorable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertTrue(
|
|
explorable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
# Verify page outside /events/ tree are not explorable
|
|
self.assertFalse(explorable_pages.filter(id=about_us_page.id).exists())
|
|
|
|
def test_explorable_pages_in_explorer(self):
|
|
event_editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
|
|
client = Client()
|
|
client.force_login(event_editor)
|
|
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
explorer_response = client.get(
|
|
f"/admin/api/main/pages/?child_of={homepage.pk}&for_explorer=1"
|
|
)
|
|
explorer_json = json.loads(explorer_response.content.decode("utf-8"))
|
|
|
|
events_page = Page.objects.get(url_path="/home/events/")
|
|
about_us_page = Page.objects.get(url_path="/home/about-us/")
|
|
|
|
explorable_titles = [t.get("title") for t in explorer_json.get("items")]
|
|
self.assertIn(events_page.title, explorable_titles)
|
|
self.assertNotIn(about_us_page.title, explorable_titles)
|
|
|
|
def test_explorable_pages_with_permission_gap_in_hierarchy(self):
|
|
corporate_editor = get_user_model().objects.get(
|
|
email="corporateeditor@example.com"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
about_us_page = Page.objects.get(url_path="/home/about-us/")
|
|
businessy_events = Page.objects.get(url_path="/home/events/businessy-events/")
|
|
events_page = Page.objects.get(url_path="/home/events/")
|
|
|
|
explorable_pages = policy.explorable_instances(corporate_editor)
|
|
|
|
self.assertTrue(explorable_pages.filter(id=about_us_page.id).exists())
|
|
self.assertTrue(explorable_pages.filter(id=businessy_events.id).exists())
|
|
self.assertTrue(explorable_pages.filter(id=events_page.id).exists())
|
|
|
|
def test_editable_pages_for_user_with_edit_permission(self):
|
|
event_moderator = get_user_model().objects.get(
|
|
email="eventmoderator@example.com"
|
|
)
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
editable_pages = policy.instances_user_has_permission_for(
|
|
event_moderator, "change"
|
|
)
|
|
can_edit_pages = policy.user_has_permission(event_moderator, "change")
|
|
publishable_pages = policy.instances_user_has_permission_for(
|
|
event_moderator, "publish"
|
|
)
|
|
can_publish_pages = policy.user_has_permission(event_moderator, "publish")
|
|
|
|
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
|
|
|
self.assertTrue(can_edit_pages)
|
|
|
|
self.assertFalse(publishable_pages.filter(id=homepage.id).exists())
|
|
self.assertTrue(publishable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(publishable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertTrue(
|
|
publishable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
self.assertTrue(can_publish_pages)
|
|
|
|
def test_editable_pages_for_inactive_user(self):
|
|
user = get_user_model().objects.get(email="inactiveuser@example.com")
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
editable_pages = policy.instances_user_has_permission_for(user, "change")
|
|
can_edit_pages = policy.user_has_permission(user, "change")
|
|
publishable_pages = policy.instances_user_has_permission_for(user, "publish")
|
|
can_publish_pages = policy.user_has_permission(user, "publish")
|
|
|
|
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
|
|
|
self.assertFalse(can_edit_pages)
|
|
|
|
self.assertFalse(publishable_pages.filter(id=homepage.id).exists())
|
|
self.assertFalse(publishable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=unpublished_event_page.id).exists()
|
|
)
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
self.assertFalse(can_publish_pages)
|
|
|
|
def test_editable_pages_for_superuser(self):
|
|
user = get_user_model().objects.get(email="superuser@example.com")
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
editable_pages = policy.instances_user_has_permission_for(user, "change")
|
|
can_edit_pages = policy.user_has_permission(user, "change")
|
|
publishable_pages = policy.instances_user_has_permission_for(user, "publish")
|
|
can_publish_pages = policy.user_has_permission(user, "publish")
|
|
|
|
self.assertTrue(editable_pages.filter(id=homepage.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertTrue(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
|
|
|
self.assertTrue(can_edit_pages)
|
|
|
|
self.assertTrue(publishable_pages.filter(id=homepage.id).exists())
|
|
self.assertTrue(publishable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertTrue(publishable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertTrue(
|
|
publishable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
self.assertTrue(can_publish_pages)
|
|
|
|
def test_editable_pages_for_non_editing_user(self):
|
|
user = get_user_model().objects.get(email="admin_only_user@example.com")
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
unpublished_event_page = EventPage.objects.get(
|
|
url_path="/home/events/tentative-unpublished-event/"
|
|
)
|
|
someone_elses_event_page = EventPage.objects.get(
|
|
url_path="/home/events/someone-elses-event/"
|
|
)
|
|
|
|
policy = PagePermissionPolicy()
|
|
|
|
editable_pages = policy.instances_user_has_permission_for(user, "change")
|
|
can_edit_pages = policy.user_has_permission(user, "change")
|
|
publishable_pages = policy.instances_user_has_permission_for(user, "publish")
|
|
can_publish_pages = policy.user_has_permission(user, "publish")
|
|
|
|
self.assertFalse(editable_pages.filter(id=homepage.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=unpublished_event_page.id).exists())
|
|
self.assertFalse(editable_pages.filter(id=someone_elses_event_page.id).exists())
|
|
|
|
self.assertFalse(can_edit_pages)
|
|
|
|
self.assertFalse(publishable_pages.filter(id=homepage.id).exists())
|
|
self.assertFalse(publishable_pages.filter(id=christmas_page.id).exists())
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=unpublished_event_page.id).exists()
|
|
)
|
|
self.assertFalse(
|
|
publishable_pages.filter(id=someone_elses_event_page.id).exists()
|
|
)
|
|
|
|
self.assertFalse(can_publish_pages)
|
|
|
|
def test_lock_page_for_superuser(self):
|
|
user = get_user_model().objects.get(email="superuser@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
locked_page = Page.objects.get(url_path="/home/my-locked-page/")
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
locked_perms = locked_page.permissions_for_user(user)
|
|
|
|
self.assertTrue(perms.can_lock())
|
|
self.assertFalse(
|
|
locked_perms.can_unpublish()
|
|
) # locked pages can't be unpublished
|
|
self.assertTrue(perms.can_unlock())
|
|
|
|
def test_lock_page_for_moderator(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertTrue(perms.can_lock())
|
|
self.assertTrue(perms.can_unlock())
|
|
|
|
def test_lock_page_for_moderator_without_unlock_permission(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
GroupPagePermission.objects.filter(
|
|
group__name="Event moderators", permission__codename="unlock_page"
|
|
).delete()
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertTrue(perms.can_lock())
|
|
self.assertFalse(perms.can_unlock())
|
|
|
|
def test_lock_page_for_moderator_whole_locked_page_without_unlock_permission(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
# Lock the page
|
|
christmas_page.locked = True
|
|
christmas_page.locked_by = user
|
|
christmas_page.locked_at = timezone.now()
|
|
christmas_page.save()
|
|
|
|
GroupPagePermission.objects.filter(
|
|
group__name="Event moderators", permission__codename="unlock_page"
|
|
).delete()
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
# Unlike in the previous test, the user can unlock this page as it was them who locked
|
|
self.assertTrue(perms.can_lock())
|
|
self.assertTrue(perms.can_unlock())
|
|
|
|
def test_lock_page_for_editor(self):
|
|
user = get_user_model().objects.get(email="eventeditor@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertFalse(perms.can_lock())
|
|
self.assertFalse(perms.can_unlock())
|
|
|
|
def test_lock_page_for_non_editing_user(self):
|
|
user = get_user_model().objects.get(email="admin_only_user@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertFalse(perms.can_lock())
|
|
self.assertFalse(perms.can_unlock())
|
|
|
|
def test_lock_page_for_editor_with_lock_permission(self):
|
|
user = get_user_model().objects.get(email="eventeditor@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
GroupPagePermission.objects.create(
|
|
group=Group.objects.get(name="Event editors"),
|
|
page=christmas_page,
|
|
permission_type="lock",
|
|
)
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertTrue(perms.can_lock())
|
|
|
|
# Still shouldn't have unlock permission
|
|
self.assertFalse(perms.can_unlock())
|
|
|
|
def test_page_locked_for_unlocked_page(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
self.assertFalse(perms.page_locked())
|
|
|
|
def test_page_locked_for_locked_page(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
# Lock the page
|
|
christmas_page.locked = True
|
|
christmas_page.locked_by = user
|
|
christmas_page.locked_at = timezone.now()
|
|
christmas_page.save()
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
# The user who locked the page shouldn't see the page as locked
|
|
self.assertFalse(perms.page_locked())
|
|
|
|
# Other users should see the page as locked
|
|
other_user = get_user_model().objects.get(email="eventeditor@example.com")
|
|
|
|
other_perms = christmas_page.permissions_for_user(other_user)
|
|
self.assertTrue(other_perms.page_locked())
|
|
|
|
@override_settings(WAGTAILADMIN_GLOBAL_EDIT_LOCK=True)
|
|
def test_page_locked_for_locked_page_with_global_lock_enabled(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
# Lock the page
|
|
christmas_page.locked = True
|
|
christmas_page.locked_by = user
|
|
christmas_page.locked_at = timezone.now()
|
|
christmas_page.save()
|
|
|
|
perms = christmas_page.permissions_for_user(user)
|
|
|
|
# The user who locked the page should now also see the page as locked
|
|
self.assertTrue(perms.page_locked())
|
|
|
|
# Other users should see the page as locked, like before
|
|
other_user = get_user_model().objects.get(email="eventeditor@example.com")
|
|
|
|
other_perms = christmas_page.permissions_for_user(other_user)
|
|
|
|
self.assertTrue(other_perms.page_locked())
|
|
|
|
def test_page_locked_in_workflow(self):
|
|
workflow, task = self.create_workflow_and_task()
|
|
editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
moderator = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
superuser = get_user_model().objects.get(email="superuser@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
christmas_page.save_revision()
|
|
workflow.start(christmas_page, editor)
|
|
|
|
moderator_perms = christmas_page.permissions_for_user(moderator)
|
|
|
|
# the moderator is in the group assigned to moderate the task, so the page should
|
|
# not be locked for them
|
|
self.assertFalse(moderator_perms.page_locked())
|
|
|
|
superuser_perms = christmas_page.permissions_for_user(superuser)
|
|
|
|
# superusers can moderate any GroupApprovalTask, so the page should not be locked
|
|
# for them
|
|
self.assertFalse(superuser_perms.page_locked())
|
|
|
|
editor_perms = christmas_page.permissions_for_user(editor)
|
|
|
|
# the editor is not in the group assigned to moderate the task, so the page should
|
|
# be locked for them
|
|
self.assertTrue(editor_perms.page_locked())
|
|
|
|
def test_page_lock_in_workflow(self):
|
|
workflow, task = self.create_workflow_and_task()
|
|
editor = get_user_model().objects.get(email="eventeditor@example.com")
|
|
moderator = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
christmas_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
christmas_page.save_revision()
|
|
workflow.start(christmas_page, editor)
|
|
|
|
moderator_perms = christmas_page.permissions_for_user(moderator)
|
|
|
|
# the moderator is in the group assigned to moderate the task, so they can lock the page, but can't unlock it
|
|
# unless they're the locker
|
|
self.assertTrue(moderator_perms.can_lock())
|
|
self.assertFalse(moderator_perms.can_unlock())
|
|
|
|
editor_perms = christmas_page.permissions_for_user(editor)
|
|
|
|
# the editor is not in the group assigned to moderate the task, so they can't lock or unlock the page
|
|
self.assertFalse(editor_perms.can_lock())
|
|
self.assertFalse(editor_perms.can_unlock())
|
|
|
|
def test_custom_permission_tester_page(self):
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
instance = CustomPermissionPage(
|
|
title="This page has a custom permission tester",
|
|
slug="page-with-custom-permission-tester",
|
|
)
|
|
homepage.add_child(instance=instance)
|
|
page = Page.objects.get(pk=instance.pk)
|
|
user = get_user_model().objects.get(email="eventeditor@example.com")
|
|
self.assertIsInstance(page.permissions_for_user(user), CustomPermissionTester)
|
|
|
|
|
|
class TestPagePermissionTesterCanCopyTo(TestCase):
|
|
"""Tests PagePermissionTester.can_copy_to()"""
|
|
|
|
fixtures = ["test.json"]
|
|
|
|
def setUp(self):
|
|
# These same pages will be used for testing the result for each user
|
|
self.board_meetings_page = BusinessSubIndex.objects.get(
|
|
url_path="/home/events/businessy-events/board-meetings/"
|
|
)
|
|
self.event_page = EventPage.objects.get(url_path="/home/events/christmas/")
|
|
|
|
# We'll also create a SingletonPageViaMaxCount to use
|
|
homepage = Page.objects.get(url_path="/home/")
|
|
self.singleton_page = SingletonPageViaMaxCount(title="there can be only one")
|
|
homepage.add_child(instance=self.singleton_page)
|
|
|
|
def test_inactive_user_cannot_copy_any_pages(self):
|
|
user = get_user_model().objects.get(email="inactiveuser@example.com")
|
|
|
|
# Create PagePermissionTester objects for this user, for each page
|
|
board_meetings_page_perms = self.board_meetings_page.permissions_for_user(user)
|
|
event_page_perms = self.event_page.permissions_for_user(user)
|
|
singleton_page_perms = self.singleton_page.permissions_for_user(user)
|
|
|
|
# This user should not be able to copy any pages
|
|
self.assertFalse(event_page_perms.can_copy_to(self.event_page.get_parent()))
|
|
self.assertFalse(
|
|
board_meetings_page_perms.can_copy_to(self.board_meetings_page.get_parent())
|
|
)
|
|
self.assertFalse(
|
|
singleton_page_perms.can_copy_to(self.singleton_page.get_parent())
|
|
)
|
|
|
|
def test_no_permissions_admin_cannot_copy_any_pages(self):
|
|
user = get_user_model().objects.get(email="admin_only_user@example.com")
|
|
|
|
# Create PagePermissionTester objects for this user, for each page
|
|
board_meetings_page_perms = self.board_meetings_page.permissions_for_user(user)
|
|
event_page_perms = self.event_page.permissions_for_user(user)
|
|
singleton_page_perms = self.singleton_page.permissions_for_user(user)
|
|
|
|
# This user should not be able to copy any pages
|
|
self.assertFalse(event_page_perms.can_copy_to(self.event_page.get_parent()))
|
|
self.assertFalse(
|
|
board_meetings_page_perms.can_copy_to(self.board_meetings_page.get_parent())
|
|
)
|
|
self.assertFalse(
|
|
singleton_page_perms.can_copy_to(self.singleton_page.get_parent())
|
|
)
|
|
|
|
def test_event_moderator_cannot_copy_a_singleton_page(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
|
|
# Create PagePermissionTester objects for this user, for each page
|
|
board_meetings_page_perms = self.board_meetings_page.permissions_for_user(user)
|
|
event_page_perms = self.event_page.permissions_for_user(user)
|
|
singleton_page_perms = self.singleton_page.permissions_for_user(user)
|
|
|
|
# We'd expect an event moderator to be able to copy an event page
|
|
self.assertTrue(event_page_perms.can_copy_to(self.event_page.get_parent()))
|
|
# This works because copying doesn't necessarily have to mean publishing
|
|
self.assertTrue(
|
|
board_meetings_page_perms.can_copy_to(self.board_meetings_page.get_parent())
|
|
)
|
|
# SingletonPageViaMaxCount.can_create_at() prevents copying, regardless of a user's permissions
|
|
self.assertFalse(
|
|
singleton_page_perms.can_copy_to(self.singleton_page.get_parent())
|
|
)
|
|
|
|
def test_not_even_a_superuser_can_copy_a_singleton_page(self):
|
|
user = get_user_model().objects.get(email="superuser@example.com")
|
|
|
|
# Create PagePermissionTester object for this user, for each page
|
|
board_meetings_page_perms = self.board_meetings_page.permissions_for_user(user)
|
|
event_page_perms = self.event_page.permissions_for_user(user)
|
|
singleton_page_perms = self.singleton_page.permissions_for_user(user)
|
|
|
|
# A superuser has full permissions, so these are self explanatory
|
|
self.assertTrue(event_page_perms.can_copy_to(self.event_page.get_parent()))
|
|
self.assertTrue(
|
|
board_meetings_page_perms.can_copy_to(self.board_meetings_page.get_parent())
|
|
)
|
|
# However, SingletonPageViaMaxCount.can_create_at() prevents copying, regardless of a user's permissions
|
|
self.assertFalse(
|
|
singleton_page_perms.can_copy_to(self.singleton_page.get_parent())
|
|
)
|
|
|
|
|
|
class TestPagePermissionModel(TestCase):
|
|
fixtures = [
|
|
"test.json",
|
|
]
|
|
|
|
def test_create_with_permission_type_only(self):
|
|
user = get_user_model().objects.get(email="eventmoderator@example.com")
|
|
page = Page.objects.get(url_path="/home/secret-plans/steal-underpants/")
|
|
group_permission = GroupPagePermission.objects.create(
|
|
group=user.groups.first(), page=page, permission_type="add"
|
|
)
|
|
self.assertEqual(group_permission.permission.codename, "add_page")
|