def test_future_go_live_page_will_not_be_published(self): page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, go_live_at=timezone.now() + timedelta(days=1), ) self.root_page.add_child(instance=page) page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) p = Page.objects.get(slug="hello-world") self.assertFalse(p.live) self.assertTrue( PageRevision.objects.filter(page=p).exclude( approved_go_live_at__isnull=True).exists()) management.call_command("publish_scheduled_pages") p = Page.objects.get(slug="hello-world") self.assertFalse(p.live) self.assertTrue( PageRevision.objects.filter(page=p).exclude( approved_go_live_at__isnull=True).exists())
def test_disable_preview_on_revisions_list(self): simple_page = SimplePage(title="simple page", content="hello") self.root_page.add_child(instance=simple_page) simple_page.save_revision(log_action=True) # check preview shows up by default response = self.client.get( reverse("wagtailadmin_pages:history", args=(simple_page.id,)) ) preview_url = reverse( "wagtailadmin_pages:revisions_view", args=(simple_page.id, simple_page.get_latest_revision().id), ) self.assertContains(response, "Preview") self.assertContains(response, preview_url) stream_page = StreamPage(title="stream page", body=[("text", "hello")]) self.root_page.add_child(instance=stream_page) latest_revision = stream_page.save_revision(log_action=True) # StreamPage has preview_modes = [] response = self.client.get( reverse("wagtailadmin_pages:history", args=(stream_page.id,)) ) preview_url = reverse( "wagtailadmin_pages:revisions_view", args=(stream_page.id, latest_revision.id), ) self.assertNotContains(response, "Preview") self.assertNotContains(response, preview_url)
class TestApproveRejectModerationWithoutUser(TestCase, WagtailTestUtils): def setUp(self): self.submitter = self.create_superuser( username="******", email="*****@*****.**", password="******", ) self.user = self.login() # Create a page and submit it for moderation root_page = Page.objects.get(id=2) self.page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, has_unpublished_changes=True, ) root_page.add_child(instance=self.page) # save_revision without user self.page.save_revision(submitted_for_moderation=True) self.revision = self.page.get_latest_revision() def test_approve_moderation_view_without_user(self): """ This posts to the approve moderation view and checks that the page was approved """ # Connect a mock signal handler to page_published signal mock_handler = mock.MagicMock() page_published.connect(mock_handler) # Post response = self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(self.revision.id,)) ) # Check that the user was redirected to the dashboard self.assertRedirects(response, reverse("wagtailadmin_home")) page = Page.objects.get(id=self.page.id) # Page must be live self.assertTrue(page.live, "Approving moderation failed to set live=True") # Page should now have no unpublished changes self.assertFalse( page.has_unpublished_changes, "Approving moderation failed to set has_unpublished_changes=False", ) # Check that the page_published signal was fired self.assertEqual(mock_handler.call_count, 1) mock_call = mock_handler.mock_calls[0][2] self.assertEqual(mock_call["sender"], self.page.specific_class) self.assertEqual(mock_call["instance"], self.page) self.assertIsInstance(mock_call["instance"], self.page.specific_class)
def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) # Add child page child_page = SimplePage( title="Hello world!", slug="hello-world", content="Some content here", ) self.root_page.add_child(instance=child_page) child_page.save_revision().publish() self.child_page = SimplePage.objects.get(id=child_page.id) self.create_superuser(username="******", password="******") self.create_superuser(username="******", password="******")
def test_go_live_page_will_be_published(self): # Connect a mock signal handler to page_published signal signal_fired = [False] signal_page = [None] def page_published_handler(sender, instance, **kwargs): signal_fired[0] = True signal_page[0] = instance page_published.connect(page_published_handler) page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, has_unpublished_changes=True, go_live_at=timezone.now() - timedelta(days=1), ) self.root_page.add_child(instance=page) page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) p = Page.objects.get(slug="hello-world") self.assertFalse(p.live) self.assertTrue( PageRevision.objects.filter(page=p).exclude( approved_go_live_at__isnull=True).exists()) management.call_command("publish_scheduled_pages") p = Page.objects.get(slug="hello-world") self.assertTrue(p.live) self.assertTrue(p.first_published_at) self.assertFalse(p.has_unpublished_changes) self.assertFalse( PageRevision.objects.filter(page=p).exclude( approved_go_live_at__isnull=True).exists()) # Check that the page_published signal was fired self.assertTrue(signal_fired[0]) self.assertEqual(signal_page[0], page) self.assertEqual(signal_page[0], signal_page[0].specific)
def test_go_live_when_newer_revision_exists(self): page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, has_unpublished_changes=True, go_live_at=timezone.now() - timedelta(days=1), ) self.root_page.add_child(instance=page) page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) page.title = "Goodbye world!" page.save_revision(submitted_for_moderation=False) management.call_command("publish_scheduled_pages") p = Page.objects.get(slug="hello-world") self.assertTrue(p.live) self.assertTrue(p.has_unpublished_changes) self.assertEqual(p.title, "Hello world!")
def test_expired_pages_are_dropped_from_mod_queue(self): page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, expire_at=timezone.now() - timedelta(days=1), ) self.root_page.add_child(instance=page) page.save_revision(submitted_for_moderation=True) p = Page.objects.get(slug="hello-world") self.assertFalse(p.live) self.assertTrue( PageRevision.objects.filter( page=p, submitted_for_moderation=True).exists()) management.call_command("publish_scheduled_pages") p = Page.objects.get(slug="hello-world") self.assertFalse( PageRevision.objects.filter( page=p, submitted_for_moderation=True).exists())
class TestEnablePreview(TestCase, WagtailTestUtils): def setUp(self): self.root_page = Page.objects.get(id=2) self.user = self.login() # SimplePage only has one preview mode self.single = SimplePage(title="Single preview mode", content="foo") # MultiPreviewModesPage has two preview modes self.multiple = MultiPreviewModesPage(title="Multiple preview modes") self.root_page.add_child(instance=self.single) self.root_page.add_child(instance=self.multiple) def get_url_on_add(self, name, page): model_name = type(page)._meta.model_name return reverse( f"wagtailadmin_pages:{name}", args=("tests", model_name, self.root_page.id), ) def get_url_on_edit(self, name, page): return reverse(f"wagtailadmin_pages:{name}", args=(page.id, )) def test_show_preview_panel_on_create_with_single_mode(self): create_url = self.get_url_on_add("add", self.single) preview_url = self.get_url_on_add("preview_on_add", self.single) iframe_url = preview_url + "?in_preview_panel=true&mode=" response = self.client.get(create_url) self.assertEqual(response.status_code, 200) # Should show the preview panel self.assertContains(response, 'data-side-panel-toggle="preview"') self.assertContains(response, 'data-side-panel="preview"') self.assertContains(response, 'data-action="%s"' % preview_url) # Should show the iframe self.assertContains( response, f'<iframe title="Preview" class="preview-panel__iframe" data-preview-iframe src="{iframe_url}" aria-describedby="preview-panel-error-banner">', ) # Should not show the preview mode selection self.assertNotContains( response, '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>', ) def test_show_preview_panel_on_create_with_multiple_modes(self): create_url = self.get_url_on_add("add", self.multiple) preview_url = self.get_url_on_add("preview_on_add", self.multiple) iframe_url = preview_url + "?in_preview_panel=true&mode=alt%231" response = self.client.get(create_url) self.assertEqual(response.status_code, 200) # Should show the preview panel self.assertContains(response, 'data-side-panel-toggle="preview"') self.assertContains(response, 'data-side-panel="preview"') self.assertContains(response, 'data-action="%s"' % preview_url) # Should show the iframe with the default mode set and correctly quoted self.assertContains( response, f'<iframe title="Preview" class="preview-panel__iframe" data-preview-iframe src="{iframe_url}" aria-describedby="preview-panel-error-banner">', ) # should show the preview mode selection self.assertContains( response, '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>', ) self.assertContains(response, '<option value="original">Original</option>') # Should respect the default_preview_mode self.assertContains( response, '<option value="alt#1" selected>Alternate</option>') def test_show_preview_panel_on_edit_with_single_mode(self): edit_url = self.get_url_on_edit("edit", self.single) preview_url = self.get_url_on_edit("preview_on_edit", self.single) iframe_url = preview_url + "?in_preview_panel=true&mode=" response = self.client.get(edit_url) self.assertEqual(response.status_code, 200) # Should show the preview panel self.assertContains(response, 'data-side-panel-toggle="preview"') self.assertContains(response, 'data-side-panel="preview"') self.assertContains(response, 'data-action="%s"' % preview_url) # Should show the iframe self.assertContains( response, f'<iframe title="Preview" class="preview-panel__iframe" data-preview-iframe src="{iframe_url}" aria-describedby="preview-panel-error-banner">', ) # Should not show the preview mode selection self.assertNotContains( response, '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>', ) def test_show_preview_panel_on_edit_with_multiple_modes(self): edit_url = self.get_url_on_edit("edit", self.multiple) preview_url = self.get_url_on_edit("preview_on_edit", self.multiple) iframe_url = preview_url + "?in_preview_panel=true&mode=alt%231" response = self.client.get(edit_url) self.assertEqual(response.status_code, 200) # Should show the preview panel self.assertContains(response, 'data-side-panel-toggle="preview"') self.assertContains(response, 'data-side-panel="preview"') self.assertContains(response, 'data-action="%s"' % preview_url) # Should show the iframe with the default mode set and correctly quoted self.assertContains( response, f'<iframe title="Preview" class="preview-panel__iframe" data-preview-iframe src="{iframe_url}" aria-describedby="preview-panel-error-banner">', ) # should show the preview mode selection self.assertContains( response, '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>', ) self.assertContains(response, '<option value="original">Original</option>') # Should respect the default_preview_mode self.assertContains( response, '<option value="alt#1" selected>Alternate</option>') def test_show_preview_on_revisions_list(self): latest_revision = self.single.save_revision(log_action=True) history_url = self.get_url_on_edit("history", self.single) preview_url = reverse( "wagtailadmin_pages:revisions_view", args=(self.single.id, latest_revision.id), ) response = self.client.get(history_url) self.assertContains(response, "Preview") self.assertContains(response, preview_url)
class TestCreateLogEntriesFromRevisionsCommand(TestCase): fixtures = ["test.json"] def setUp(self): self.page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, expire_at=timezone.now() - timedelta(days=1), ) Page.objects.get(id=2).add_child(instance=self.page) # Create empty revisions, which should not be converted to log entries for i in range(3): self.page.save_revision() # Add another revision with a content change self.page.title = "Hello world!!" revision = self.page.save_revision() revision.publish() # Do the same with a SecretPage (to check that the version comparison code doesn't # trip up on permission-dependent edit handlers) self.secret_page = SecretPage( title="The moon", slug="the-moon", boring_data="the moon", secret_data="is made of cheese", live=False, ) Page.objects.get(id=2).add_child(instance=self.secret_page) # Create empty revisions, which should not be converted to log entries for i in range(3): self.secret_page.save_revision() # Add another revision with a content change self.secret_page.secret_data = "is flat" revision = self.secret_page.save_revision() revision.publish() # clean up log entries PageLogEntry.objects.all().delete() def test_log_entries_created_from_revisions(self): management.call_command("create_log_entries_from_revisions") # Should not create entries for empty revisions. self.assertListEqual( list(PageLogEntry.objects.values_list("action", flat=True)), [ "wagtail.publish", "wagtail.edit", "wagtail.create", "wagtail.publish", "wagtail.edit", "wagtail.create", ], ) def test_command_doesnt_crash_for_revisions_without_page_model(self): with mock.patch( "wagtail.models.ContentType.model_class", return_value=None, ): management.call_command("create_log_entries_from_revisions") self.assertEqual(PageLogEntry.objects.count(), 0)
class TestPurgeRevisionsCommand(TestCase): fixtures = ["test.json"] def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) self.page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, ) self.root_page.add_child(instance=self.page) self.page.refresh_from_db() def run_command(self, days=None): if days: days_input = "--days=" + str(days) return management.call_command("purge_revisions", days_input, stdout=StringIO()) return management.call_command("purge_revisions", stdout=StringIO()) def test_latest_revision_not_purged(self): revision_1 = self.page.save_revision() revision_2 = self.page.save_revision() self.run_command() # revision 1 should be deleted, revision 2 should not be self.assertNotIn(revision_1, PageRevision.objects.filter(page=self.page)) self.assertIn(revision_2, PageRevision.objects.filter(page=self.page)) def test_revisions_in_moderation_not_purged(self): self.page.save_revision(submitted_for_moderation=True) revision = self.page.save_revision() self.run_command() self.assertTrue( PageRevision.objects.filter( page=self.page, submitted_for_moderation=True).exists()) try: from wagtail.models import Task, Workflow, WorkflowTask workflow = Workflow.objects.create(name="test_workflow") task_1 = Task.objects.create(name="test_task_1") user = get_user_model().objects.first() WorkflowTask.objects.create(workflow=workflow, task=task_1, sort_order=1) workflow.start(self.page, user) self.page.save_revision() self.run_command() # even though no longer the latest revision, the old revision should stay as it is # attached to an in progress workflow self.assertIn(revision, PageRevision.objects.filter(page=self.page)) except ImportError: pass def test_revisions_with_approve_go_live_not_purged(self): approved_revision = self.page.save_revision( approved_go_live_at=timezone.now() + timedelta(days=1)) self.page.save_revision() self.run_command() self.assertIn(approved_revision, PageRevision.objects.filter(page=self.page)) def test_purge_revisions_with_date_cutoff(self): old_revision = self.page.save_revision() self.page.save_revision() self.run_command(days=30) # revision should not be deleted, as it is younger than 30 days self.assertIn(old_revision, PageRevision.objects.filter(page=self.page)) old_revision.created_at = timezone.now() - timedelta(days=31) old_revision.save() self.run_command(days=30) # revision is now older than 30 days, so should be deleted self.assertNotIn(old_revision, PageRevision.objects.filter(page=self.page))
class TestNotificationPreferences(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) # Login self.user = self.login() # Create two moderator users for testing 'submitted' email self.moderator = self.create_superuser("moderator", "*****@*****.**", "password") self.moderator2 = self.create_superuser("moderator2", "*****@*****.**", "password") # Create a submitter for testing 'rejected' and 'approved' emails self.submitter = self.create_user("submitter", "*****@*****.**", "password") # User profiles for moderator2 and the submitter self.moderator2_profile = UserProfile.get_for_user(self.moderator2) self.submitter_profile = UserProfile.get_for_user(self.submitter) # Create a page and submit it for moderation self.child_page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, ) self.root_page.add_child(instance=self.child_page) # POST data to edit the page self.post_data = { "title": "I've been edited!", "content": "Some content", "slug": "hello-world", "action-submit": "Submit", } def submit(self): return self.client.post( reverse("wagtailadmin_pages:edit", args=(self.child_page.id, )), self.post_data, ) def silent_submit(self): """ Sets up the child_page as needing moderation, without making a request """ self.child_page.save_revision(user=self.submitter, submitted_for_moderation=True) self.revision = self.child_page.get_latest_revision() def approve(self): return self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(self.revision.id, ))) def reject(self): return self.client.post( reverse("wagtailadmin_pages:reject_moderation", args=(self.revision.id, ))) def test_vanilla_profile(self): # Check that the vanilla profile has rejected notifications on self.assertIs(self.submitter_profile.rejected_notifications, True) # Check that the vanilla profile has approved notifications on self.assertIs(self.submitter_profile.approved_notifications, True) def test_approved_notifications(self): # Set up the page version self.silent_submit() # Approve self.approve() # Submitter must receive an approved email self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].to, ["*****@*****.**"]) self.assertEqual(mail.outbox[0].subject, 'The page "Hello world!" has been approved') def test_approved_notifications_preferences_respected(self): # Submitter doesn't want 'approved' emails self.submitter_profile.approved_notifications = False self.submitter_profile.save() # Set up the page version self.silent_submit() # Approve self.approve() # No email to send self.assertEqual(len(mail.outbox), 0) def test_rejected_notifications(self): # Set up the page version self.silent_submit() # Reject self.reject() # Submitter must receive a rejected email self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].to, ["*****@*****.**"]) self.assertEqual(mail.outbox[0].subject, 'The page "Hello world!" has been rejected') def test_rejected_notification_preferences_respected(self): # Submitter doesn't want 'rejected' emails self.submitter_profile.rejected_notifications = False self.submitter_profile.save() # Set up the page version self.silent_submit() # Reject self.reject() # No email to send self.assertEqual(len(mail.outbox), 0) @override_settings(WAGTAILADMIN_NOTIFICATION_INCLUDE_SUPERUSERS=False) def test_disable_superuser_notification(self): # Add one of the superusers to the moderator group self.moderator.groups.add(Group.objects.get(name="Moderators")) response = self.submit() # Should be redirected to explorer page self.assertEqual(response.status_code, 302) # Check that the non-moderator superuser is not being notified expected_emails = 1 self.assertEqual(len(mail.outbox), expected_emails) # Use chain as the 'to' field is a list of recipients email_to = list(chain.from_iterable([m.to for m in mail.outbox])) self.assertIn(self.moderator.email, email_to) self.assertNotIn(self.moderator2.email, email_to) @mock.patch.object(EmailMultiAlternatives, "send", side_effect=IOError("Server down")) def test_email_send_error(self, mock_fn): logging.disable(logging.CRITICAL) # Approve self.silent_submit() response = self.approve() logging.disable(logging.NOTSET) # An email that fails to send should return a message rather than crash the page self.assertEqual(response.status_code, 302) response = self.client.get(reverse("wagtailadmin_home")) # There should be one "approved" message and one "failed to send notifications" messages = list(response.context["messages"]) self.assertEqual(len(messages), 2) self.assertEqual(messages[0].level, message_constants.SUCCESS) self.assertEqual(messages[1].level, message_constants.ERROR) def test_email_headers(self): # Submit self.submit() msg_headers = set(mail.outbox[0].message().items()) headers = {("Auto-Submitted", "auto-generated")} self.assertTrue( headers.issubset(msg_headers), msg="Message is missing the Auto-Submitted header.", )
class TestApproveRejectModeration(TestCase, WagtailTestUtils): def setUp(self): self.submitter = self.create_superuser( username="******", email="*****@*****.**", password="******", ) self.user = self.login() # Create a page and submit it for moderation root_page = Page.objects.get(id=2) self.page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, has_unpublished_changes=True, ) root_page.add_child(instance=self.page) self.page.save_revision(user=self.submitter, submitted_for_moderation=True) self.revision = self.page.get_latest_revision() def test_approve_moderation_view(self): """ This posts to the approve moderation view and checks that the page was approved """ # Connect a mock signal handler to page_published signal mock_handler = mock.MagicMock() page_published.connect(mock_handler) # Post response = self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(self.revision.id, ))) # Check that the user was redirected to the dashboard self.assertRedirects(response, reverse("wagtailadmin_home")) page = Page.objects.get(id=self.page.id) # Page must be live self.assertTrue(page.live, "Approving moderation failed to set live=True") # Page should now have no unpublished changes self.assertFalse( page.has_unpublished_changes, "Approving moderation failed to set has_unpublished_changes=False", ) # Check that the page_published signal was fired self.assertEqual(mock_handler.call_count, 1) mock_call = mock_handler.mock_calls[0][2] self.assertEqual(mock_call["sender"], self.page.specific_class) self.assertEqual(mock_call["instance"], self.page) self.assertIsInstance(mock_call["instance"], self.page.specific_class) def test_approve_moderation_when_later_revision_exists(self): self.page.title = "Goodbye world!" self.page.save_revision(user=self.submitter, submitted_for_moderation=False) response = self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(self.revision.id, ))) # Check that the user was redirected to the dashboard self.assertRedirects(response, reverse("wagtailadmin_home")) page = Page.objects.get(id=self.page.id) # Page must be live self.assertTrue(page.live, "Approving moderation failed to set live=True") # Page content should be the submitted version, not the published one self.assertEqual(page.title, "Hello world!") # Page should still have unpublished changes self.assertTrue( page.has_unpublished_changes, "has_unpublished_changes incorrectly cleared on approve_moderation when a later revision exists", ) def test_approve_moderation_view_bad_revision_id(self): """ This tests that the approve moderation view handles invalid revision ids correctly """ # Post response = self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(12345, ))) # Check that the user received a 404 response self.assertEqual(response.status_code, 404) def test_approve_moderation_view_bad_permissions(self): """ This tests that the approve moderation view doesn't allow users without moderation permissions """ # Remove privileges from user self.user.is_superuser = False self.user.user_permissions.add( Permission.objects.get(content_type__app_label="wagtailadmin", codename="access_admin")) self.user.save() # Post response = self.client.post( reverse("wagtailadmin_pages:approve_moderation", args=(self.revision.id, ))) # Check that the user received a 302 redirected response self.assertEqual(response.status_code, 302) def test_reject_moderation_view(self): """ This posts to the reject moderation view and checks that the page was rejected """ # Post response = self.client.post( reverse("wagtailadmin_pages:reject_moderation", args=(self.revision.id, ))) # Check that the user was redirected to the dashboard self.assertRedirects(response, reverse("wagtailadmin_home")) # Page must not be live self.assertFalse(Page.objects.get(id=self.page.id).live) # Revision must no longer be submitted for moderation self.assertFalse( PageRevision.objects.get( id=self.revision.id).submitted_for_moderation) def test_reject_moderation_view_bad_revision_id(self): """ This tests that the reject moderation view handles invalid revision ids correctly """ # Post response = self.client.post( reverse("wagtailadmin_pages:reject_moderation", args=(12345, ))) # Check that the user received a 404 response self.assertEqual(response.status_code, 404) def test_reject_moderation_view_bad_permissions(self): """ This tests that the reject moderation view doesn't allow users without moderation permissions """ # Remove privileges from user self.user.is_superuser = False self.user.user_permissions.add( Permission.objects.get(content_type__app_label="wagtailadmin", codename="access_admin")) self.user.save() # Post response = self.client.post( reverse("wagtailadmin_pages:reject_moderation", args=(self.revision.id, ))) # Check that the user received a 302 redirected response self.assertEqual(response.status_code, 302) def test_preview_for_moderation(self): response = self.client.get( reverse("wagtailadmin_pages:preview_for_moderation", args=(self.revision.id, ))) # Check response self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "tests/simple_page.html") self.assertContains(response, "Hello world!")
class TestAuditLogAdmin(TestCase, WagtailTestUtils): def setUp(self): self.root_page = Page.objects.get(id=2) self.hello_page = SimplePage( title="Hello world!", slug="hello-world", content="hello", live=False, ) self.root_page.add_child(instance=self.hello_page) self.about_page = SimplePage(title="About", slug="about", content="hello") self.root_page.add_child(instance=self.about_page) self.administrator = self.create_superuser( username="******", email="*****@*****.**", password="******", ) self.editor = self.create_user( username="******", email="*****@*****.**", password="******" ) sub_editors = Group.objects.create(name="Sub editors") sub_editors.permissions.add( Permission.objects.get( content_type__app_label="wagtailadmin", codename="access_admin" ) ) self.editor.groups.add(sub_editors) for permission_type in ["add", "edit", "publish"]: GroupPagePermission.objects.create( group=sub_editors, page=self.hello_page, permission_type=permission_type ) def _update_page(self, page): # save revision page.save_revision(user=self.editor, log_action=True) # schedule for publishing page.go_live_at = timezone.now() + timedelta(seconds=1) revision = page.save_revision(user=self.editor, log_action=True) revision.publish(user=self.editor) # publish with freeze_time(timezone.now() + timedelta(seconds=2)): revision.publish(user=self.editor) # lock/unlock page.save(user=self.editor, log_action="wagtail.lock") page.save(user=self.editor, log_action="wagtail.unlock") # change privacy restriction = PageViewRestriction( page=page, restriction_type=PageViewRestriction.LOGIN ) restriction.save(user=self.editor) restriction.restriction_type = PageViewRestriction.PASSWORD restriction.save(user=self.administrator) restriction.delete() def test_page_history(self): self._update_page(self.hello_page) history_url = reverse( "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id} ) self.login(user=self.editor) response = self.client.get(history_url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Created", 1) self.assertContains(response, "Draft saved", 2) self.assertContains(response, "Locked", 1) self.assertContains(response, "Unlocked", 1) self.assertContains(response, "Page scheduled for publishing", 1) self.assertContains(response, "Published", 1) self.assertContains( response, "Added the 'Private, accessible to logged-in users' view restriction", ) self.assertContains( response, "Updated the view restriction to 'Private, accessible with the following password'", ) self.assertContains( response, "Removed the 'Private, accessible with the following password' view restriction", ) self.assertContains( response, "system", 2 ) # create without a user + remove restriction self.assertContains( response, "the_editor", 9 ) # 7 entries by editor + 1 in sidebar menu + 1 in filter self.assertContains( response, "administrator", 2 ) # the final restriction change + filter def test_page_history_filters(self): self.login(user=self.editor) self._update_page(self.hello_page) history_url = reverse( "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id} ) response = self.client.get(history_url + "?action=wagtail.edit") self.assertEqual(response.status_code, 200) self.assertContains(response, "Draft saved", count=2) self.assertNotContains(response, "Locked") self.assertNotContains(response, "Unlocked") self.assertNotContains(response, "Page scheduled for publishing") self.assertNotContains(response, "Published") def test_site_history(self): self._update_page(self.hello_page) self.about_page.save_revision(user=self.administrator, log_action=True) self.about_page.delete(user=self.administrator) site_history_url = reverse("wagtailadmin_reports:site_history") # the editor has access to the root page, so should see everything self.login(user=self.editor) response = self.client.get(site_history_url) self.assertEqual(response.status_code, 200) self.assertNotContains(response, "About") self.assertContains(response, "Draft saved", 2) self.assertNotContains(response, "Deleted") # once a page is deleted, its log entries are only visible to super admins or users with # permissions on the root page self.hello_page.delete(user=self.administrator) response = self.client.get(site_history_url) self.assertContains(response, "No log entries found") # add the editor user to the Editors group which has permissions on the root page self.editor.groups.add(Group.objects.get(name="Editors")) response = self.client.get(site_history_url) self.assertContains(response, "About", 3) # create, save draft, delete self.assertContains(response, "Created", 2) self.assertContains(response, "Deleted", 2) # check with super admin self.login(user=self.administrator) response = self.client.get(site_history_url) self.assertContains(response, "About", 3) # create, save draft, delete self.assertContains(response, "Deleted", 2) def test_history_with_deleted_user(self): self._update_page(self.hello_page) expected_deleted_string = f"user {self.editor.pk} (deleted)" self.editor.delete() self.login(user=self.administrator) # check page history response = self.client.get( reverse( "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id} ) ) self.assertContains(response, expected_deleted_string) # check site history response = self.client.get(reverse("wagtailadmin_reports:site_history")) self.assertContains(response, expected_deleted_string) def test_edit_form_has_history_link(self): self.hello_page.save_revision() self.login(user=self.editor) response = self.client.get( reverse("wagtailadmin_pages:edit", args=[self.hello_page.id]) ) self.assertEqual(response.status_code, 200) history_url = reverse("wagtailadmin_pages:history", args=[self.hello_page.id]) self.assertContains(response, history_url) def test_create_and_publish_does_not_log_revision_save(self): self.login(user=self.administrator) post_data = { "title": "New page!", "content": "Some content", "slug": "hello-world-redux", "action-publish": "action-publish", } response = self.client.post( reverse( "wagtailadmin_pages:add", args=("tests", "simplepage", self.root_page.id), ), post_data, follow=True, ) self.assertEqual(response.status_code, 200) page_id = Page.objects.get( path__startswith=self.root_page.path, slug="hello-world-redux" ).id self.assertListEqual( list( PageLogEntry.objects.filter(page=page_id).values_list( "action", flat=True ) ), ["wagtail.publish", "wagtail.create"], ) def test_revert_and_publish_logs_reversion_and_publish(self): revision = self.hello_page.save_revision(user=self.editor) self.hello_page.save_revision(user=self.editor) self.login(user=self.administrator) response = self.client.post( reverse("wagtailadmin_pages:edit", args=(self.hello_page.id,)), { "title": "Hello World!", "content": "another hello", "slug": "hello-world", "revision": revision.id, "action-publish": "action-publish", }, follow=True, ) self.assertEqual(response.status_code, 200) entries = PageLogEntry.objects.filter(page=self.hello_page).values_list( "action", flat=True ) self.assertListEqual( list(entries), ["wagtail.publish", "wagtail.rename", "wagtail.revert", "wagtail.create"], )
class TestModerationList(TestCase, WagtailTestUtils): """Test moderation list rendered by `wagtailadmin_home` view""" def setUp(self): # Create a submitter submitter = self.create_user( username="******", email="*****@*****.**", password="******", ) # Find root page self.root_page = Page.objects.get(id=2) # Create a page self.page = SimplePage( title="Wagtail, the powerful CMS for modern websites", slug="wagtail", content="Fast, elegant, open source", ) self.root_page.add_child(instance=self.page) # Submit it for moderation self.page.save_revision(user=submitter, submitted_for_moderation=True) # Create a revision self.revision = self.page.get_latest_revision() self.edit_page_url = reverse("wagtailadmin_pages:edit", args=(self.revision.page.id, )) self.preview_page_url = reverse( "wagtailadmin_pages:preview_for_moderation", args=(self.revision.id, )) def login_as_moderator_without_edit(self): # Create moderators group without edit permissions moderators_group = Group.objects.create(name="Moderators without edit") admin_permission = Permission.objects.get( content_type__app_label="wagtailadmin", codename="access_admin") moderators_group.permissions.add(admin_permission) # Create group permissions GroupPagePermission.objects.create( group=moderators_group, page=self.root_page, permission_type="publish", ) # Create a moderator without edit permissions moderator = self.create_user(username="******", email="*****@*****.**", password="******") moderator.groups.add(moderators_group) self.login(moderator) def get(self): return self.client.get(reverse("wagtailadmin_home")) def test_edit_page(self): # Login as moderator self.login() response = self.get() self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "wagtailadmin/home.html") # Check response self.assertContains(response, self.edit_page_url, count=2) # page should contain Approve and Reject forms including a valid CSRF token self.assertRegex( response.content.decode("utf-8"), r'<input type="hidden" name="csrfmiddlewaretoken" value="\w+">', ) def test_preview_for_moderation(self): # Login as moderator without edit permissions self.login_as_moderator_without_edit() response = self.get() self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "wagtailadmin/home.html") # Check response self.assertContains(response, self.preview_page_url, count=2) self.assertNotContains(response, self.edit_page_url)