From 6961f33078e12467fe7c4d1c2cfa055eace1aaca Mon Sep 17 00:00:00 2001 From: Kees Hink Date: Wed, 22 Mar 2017 12:59:07 +0100 Subject: [PATCH] Restrict view_draft to can_publish / can_edit permissions (#3474) --- CHANGELOG.txt | 1 + .../administrator_tasks/managing_users.rst | 18 +++--- docs/releases/1.10.rst | 1 + docs/topics/permissions.rst | 1 + .../wagtailadmin/tests/test_pages_views.py | 58 +++++++++++++++++++ wagtail/wagtailadmin/views/pages.py | 3 + 6 files changed, 73 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index db18f9ac2..e06b0470a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -24,6 +24,7 @@ Changelog * Tag input fields now accept spaces in tags by default, and can be overridden with the `TAG_SPACES_ALLOWED` setting (Kees Hink, Alex Gleason) * Page chooser widgets now display the required page type where relevant (Christine Ho) * Site root pages are now indicated with a globe icon in the explorer listing (Nick Smith, Huub Bouma) + * Draft page view is now restricted to users with edit / publish permission over the page (Kees Hink) * Fix: Marked 'Date from' / 'Date to' strings in wagtailforms for translation (Vorlif) * Fix: "File" field label on image edit form is now translated (Stein Strindhaug) * Fix: Unreliable preview is now reliable by always opening in a new window (Kjartan Sverrisson) diff --git a/docs/editor_manual/administrator_tasks/managing_users.rst b/docs/editor_manual/administrator_tasks/managing_users.rst index b6f70f9f7..fce7dcbd5 100644 --- a/docs/editor_manual/administrator_tasks/managing_users.rst +++ b/docs/editor_manual/administrator_tasks/managing_users.rst @@ -20,13 +20,13 @@ Clicking on a user's name will open their profile details. From here you can the Click the 'Roles' tab to edit the level of access your users have. By default there are three roles: -+--------------+--------------+-----------------+-----------------+ -| Role | Create drafts| Publish content | Access Settings | -+==============+==============+=================+=================+ -| Editor | Yes | No | No | -+--------------+--------------+-----------------+-----------------+ -| Moderator | Yes | Yes | No | -+--------------+--------------+-----------------+-----------------+ -| Administrator| Yes | Yes | Yes | -+--------------+--------------+-----------------+-----------------+ ++--------------+--------------------+-----------------+-----------------+ +| Role | Create/view drafts | Publish content | Access Settings | ++==============+====================+=================+=================+ +| Editor | Yes | No | No | ++--------------+--------------------+-----------------+-----------------+ +| Moderator | Yes | Yes | No | ++--------------+--------------------+-----------------+-----------------+ +| Administrator| Yes | Yes | Yes | ++--------------+--------------------+-----------------+-----------------+ diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index d8c818a48..7e9b65238 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -31,6 +31,7 @@ Other features * Tag input fields now accept spaces in tags by default, and can be overridden with the ``TAG_SPACES_ALLOWED`` setting (Kees Hink, Alex Gleason) * Page chooser widgets now display the required page type where relevant (Christine Ho) * Site root pages are now indicated with a globe icon in the explorer listing (Nick Smith, Huub Bouma) + * Draft page view is now restricted to users with edit / publish permission over the page (Kees Hink) Bug fixes diff --git a/docs/topics/permissions.rst b/docs/topics/permissions.rst index be6e97b51..517168d4d 100644 --- a/docs/topics/permissions.rst +++ b/docs/topics/permissions.rst @@ -31,6 +31,7 @@ The full set of available permission types is as follows: * **Bulk delete** - allows a user to delete pages that have descendants, in a single operation. Without this permission, a user has to delete the descendant pages individually before deleting the parent. This is a safeguard against accidental deletion. This permission must be used in conjunction with 'add' / 'edit' permission, as it does not provide any deletion rights of its own; it only provides a 'shortcut' for the permissions the user has already. For example, a user with just 'add' and 'bulk delete' permissions will only be able to bulk-delete if all the affected pages are owned by that user, and are unpublished. * **Lock** - grants the ability to lock or unlock this page (and any pages underneath it) for editing, preventing users from making any further edits to it. +Drafts can be viewed only if the user has either Edit or Publish permission. Image / document permissions ---------------------------- diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py index c98f22db7..4aa750d99 100644 --- a/wagtail/wagtailadmin/tests/test_pages_views.py +++ b/wagtail/wagtailadmin/tests/test_pages_views.py @@ -4080,3 +4080,61 @@ class TestValidationErrorMessages(TestCase, WagtailTestUtils): self.assertContains(response, """

This field is required.

""", count=1, html=True) # Error on title shown in the header message self.assertContains(response, "
  • Title: This field is required.
  • ", count=1) + + +class TestDraftAccess(TestCase, WagtailTestUtils): + """Tests for the draft view access restrictions.""" + + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + # Add child page + self.child_page = SimplePage( + title="Hello world!", + slug="hello-world", + content="hello", + ) + self.root_page.add_child(instance=self.child_page) + + # create user with admin access (but not draft_view access) + user = get_user_model().objects.create_user(username='bob', email='bob@email.com', password='password') + user.user_permissions.add( + Permission.objects.get(content_type__app_label='wagtailadmin', codename='access_admin') + ) + + def test_draft_access_admin(self): + """Test that admin can view draft.""" + # Login as admin + self.user = self.login() + + # Try getting page draft + response = self.client.get(reverse('wagtailadmin_pages:view_draft', args=(self.child_page.id, ))) + + # User can view + self.assertEqual(response.status_code, 200) + + def test_draft_access_unauthorized(self): + """Test that user without edit/publish permission can't view draft.""" + self.assertTrue(self.client.login(username='bob', password='password')) + + # Try getting page draft + response = self.client.get(reverse('wagtailadmin_pages:view_draft', args=(self.child_page.id, ))) + + # User gets Unauthorized response + self.assertEqual(response.status_code, 403) + + def test_draft_access_authorized(self): + """Test that user with edit permission can view draft.""" + # give user the permission to edit page + user = get_user_model().objects.get(username='bob') + user.groups.add(Group.objects.get(name='Moderators')) + user.save() + + self.assertTrue(self.client.login(username='bob', password='password')) + + # Get add subpage page + response = self.client.get(reverse('wagtailadmin_pages:view_draft', args=(self.child_page.id, ))) + + # User can view + self.assertEqual(response.status_code, 200) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 35b41a33d..1c0e4fcab 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -543,6 +543,9 @@ def delete(request, page_id): def view_draft(request, page_id): page = get_object_or_404(Page, id=page_id).get_latest_revision_as_page() + perms = page.permissions_for_user(request.user) + if not (perms.can_publish() or perms.can_edit()): + raise PermissionDenied return page.serve_preview(page.dummy_request(request), page.default_preview_mode)