diff --git a/wagtail/admin/tests/pages/test_view_draft.py b/wagtail/admin/tests/pages/test_view_draft.py index 8f1bd959b1..fcc55fb28a 100644 --- a/wagtail/admin/tests/pages/test_view_draft.py +++ b/wagtail/admin/tests/pages/test_view_draft.py @@ -4,7 +4,7 @@ from django.test import TestCase from django.urls import reverse from wagtail.core.models import Page -from wagtail.tests.testapp.models import SimplePage +from wagtail.tests.testapp.models import SimplePage, StreamPage from wagtail.tests.utils import WagtailTestUtils @@ -23,6 +23,10 @@ class TestDraftAccess(TestCase, WagtailTestUtils): ) self.root_page.add_child(instance=self.child_page) + # Add stream page (which has empty preview_modes, and so doesn't allow viewing draft) + self.stream_page = StreamPage(title='stream page', body=[('text', 'hello')]) + self.root_page.add_child(instance=self.stream_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( @@ -40,6 +44,16 @@ class TestDraftAccess(TestCase, WagtailTestUtils): # User can view self.assertEqual(response.status_code, 200) + def test_page_without_preview_modes_is_unauthorized(self): + # Login as admin + self.user = self.login() + + # Try getting page draft + response = self.client.get(reverse('wagtailadmin_pages:view_draft', args=(self.stream_page.id, ))) + + # Unauthorized response (because this page type has previewing disabled) + self.assertEqual(response.status_code, 403) + 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')) diff --git a/wagtail/admin/views/pages.py b/wagtail/admin/views/pages.py index 2a82a9d5d0..1f937dcc72 100644 --- a/wagtail/admin/views/pages.py +++ b/wagtail/admin/views/pages.py @@ -615,7 +615,13 @@ def view_draft(request, page_id): perms = page.permissions_for_user(request.user) if not (perms.can_publish() or perms.can_edit()): raise PermissionDenied - return page.make_preview_request(request, page.default_preview_mode) + + try: + preview_mode = page.default_preview_mode + except IndexError: + raise PermissionDenied + + return page.make_preview_request(request, preview_mode) class PreviewOnEdit(View): @@ -676,7 +682,12 @@ class PreviewOnEdit(View): return self.error_response(page) form.save(commit=False) - preview_mode = request.GET.get('mode', page.default_preview_mode) + + try: + preview_mode = request.GET.get('mode', page.default_preview_mode) + except IndexError: + raise PermissionDenied + return page.make_preview_request(request, preview_mode) @@ -1085,7 +1096,12 @@ def preview_for_moderation(request, revision_id): page = revision.as_page_object() - return page.make_preview_request(request, page.default_preview_mode, extra_request_attrs={ + try: + preview_mode = page.default_preview_mode + except IndexError: + raise PermissionDenied + + return page.make_preview_request(request, preview_mode, extra_request_attrs={ 'revision_id': revision_id }) @@ -1215,7 +1231,12 @@ def revisions_view(request, page_id, revision_id): revision = get_object_or_404(page.revisions, id=revision_id) revision_page = revision.as_page_object() - return revision_page.make_preview_request(request, page.default_preview_mode) + try: + preview_mode = page.default_preview_mode + except IndexError: + raise PermissionDenied + + return revision_page.make_preview_request(request, preview_mode) def revisions_compare(request, page_id, revision_id_a, revision_id_b): diff --git a/wagtail/core/models.py b/wagtail/core/models.py index 8b7184bf89..02cd188fb3 100644 --- a/wagtail/core/models.py +++ b/wagtail/core/models.py @@ -1402,6 +1402,10 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase): @property def default_preview_mode(self): + """ + The preview mode to use in workflows that do not give the user the option of selecting a + mode explicitly, e.g. moderator approval. Will raise IndexError if preview_modes is empty + """ return self.preview_modes[0][0] def is_previewable(self):