Files
old-saburly-wagtail-web/env/lib/python3.10/site-packages/wagtail/admin/tests/test_dashboard.py
2024-08-27 20:33:44 +02:00

405 lines
15 KiB
Python

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from freezegun import freeze_time
from wagtail.admin.views.home import (
LockedPagesPanel,
RecentEditsPanel,
UserObjectsInWorkflowModerationPanel,
WorkflowObjectsToModeratePanel,
)
from wagtail.coreutils import get_dummy_request
from wagtail.models import GroupPagePermission, Page, Workflow, WorkflowContentType
from wagtail.test.testapp.models import FullFeaturedSnippet, SimplePage
from wagtail.test.utils import WagtailTestUtils
class TestRecentEditsPanel(WagtailTestUtils, TestCase):
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)
self.revision = child_page.save_revision()
self.revision.publish()
self.child_page = SimplePage.objects.get(id=child_page.id)
self.user_alice = self.create_superuser(username="alice", password="password")
self.create_superuser(username="bob", password="password")
def change_something(self, title):
post_data = {"title": title, "content": "Some content", "slug": "hello-world"}
response = self.client.post(
reverse("wagtailadmin_pages:edit", args=(self.child_page.id,)), post_data
)
# Should be redirected to edit page
self.assertRedirects(
response, reverse("wagtailadmin_pages:edit", args=(self.child_page.id,))
)
# The page should have "has_unpublished_changes" flag set
child_page_new = SimplePage.objects.get(id=self.child_page.id)
self.assertTrue(child_page_new.has_unpublished_changes)
def go_to_dashboard_response(self):
response = self.client.get(reverse("wagtailadmin_home"))
self.assertEqual(response.status_code, 200)
return response
def test_your_recent_edits(self):
# Login as Bob
self.login(username="bob", password="password")
# Bob hasn't edited anything yet
response = self.client.get(reverse("wagtailadmin_home"))
self.assertNotIn("Your most recent edits", response.content.decode("utf-8"))
# Login as Alice
self.client.logout()
self.login(username="alice", password="password")
# Alice changes something
self.change_something("Alice's edit")
# Edit should show up on dashboard
response = self.go_to_dashboard_response()
self.assertIn("Your most recent edits", response.content.decode("utf-8"))
# Bob changes something
self.login(username="bob", password="password")
self.change_something("Bob's edit")
# Edit shows up on Bobs dashboard
response = self.go_to_dashboard_response()
self.assertIn("Your most recent edits", response.content.decode("utf-8"))
# Login as Alice again
self.client.logout()
self.login(username="alice", password="password")
# Alice's dashboard should still list that first edit
response = self.go_to_dashboard_response()
self.assertIn("Your most recent edits", response.content.decode("utf-8"))
def test_missing_page_record(self):
# Ensure that the panel still renders when one of the page IDs returned from querying
# PageLogEntry has no corresponding Page object. This can happen if a page is deleted,
# because PageLogEntry records are kept on deletion.
self.login(username="alice", password="password")
self.change_something("Alice's edit")
self.child_page.delete()
response = self.client.get(reverse("wagtailadmin_home"))
self.assertEqual(response.status_code, 200)
def test_panel(self):
"""Test if the panel actually returns expected pages"""
self.login(username="bob", password="password")
# change a page
edit_timestamp = timezone.now()
with freeze_time(edit_timestamp):
self.change_something("Bob's edit")
# set a user to 'mock' a request
self.client.user = get_user_model().objects.get(email="bob@example.com")
# get the panel to get the last edits
panel = RecentEditsPanel()
ctx = panel.get_context_data({"request": self.client})
page = Page.objects.get(pk=self.child_page.id).specific
# check the timestamp matches the edit
self.assertEqual(ctx["last_edits"][0][0], edit_timestamp)
# check if the page in this list is the specific page
self.assertEqual(ctx["last_edits"][0][1], page)
def test_copying_does_not_count_as_an_edit(self):
self.login(username="bob", password="password")
# change a page
self.change_something("Bob was ere")
# copy the page
post_data = {
"new_title": "Goodbye world!",
"new_slug": "goodbye-world",
"new_parent_page": str(self.root_page.id),
"copy_subpages": False,
"alias": False,
}
self.client.post(
reverse("wagtailadmin_pages:copy", args=(self.child_page.id,)), post_data
)
# check that page has been copied
self.assertTrue(Page.objects.get(title="Goodbye world!"))
response = self.client.get(reverse("wagtailadmin_home"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Your most recent edits")
self.assertContains(response, "Bob was ere")
self.assertNotContains(response, "Goodbye world!")
class TestRecentEditsQueryCount(WagtailTestUtils, TestCase):
fixtures = ["test.json"]
def setUp(self):
self.bob = self.create_superuser(username="bob", password="password")
self.dummy_request = get_dummy_request()
self.dummy_request.user = self.bob
workflow = Workflow.objects.first()
workflow_pages = {5, 6}
locked_pages = {6, 9}
scheduled_pages = {9, 12}
# make a bunch of page edits (all to EventPages, so that calls to specific() don't add
# an unpredictable number of queries)
pages_to_edit = list(
Page.objects.filter(id__in=[4, 5, 6, 9, 12, 13]).order_by("pk").specific()
)
for page in pages_to_edit:
revision = page.save_revision(user=self.bob, log_action=True)
if page.pk in workflow_pages:
workflow.start(page, self.bob)
if page.pk in locked_pages:
page.locked = True
page.locked_by = self.bob
page.locked_at = timezone.now()
page.save()
if page.pk in scheduled_pages:
revision.approved_go_live_at = timezone.now()
revision.save()
def test_panel_query_count(self):
panel = RecentEditsPanel()
parent_context = {"request": self.dummy_request}
# Warm up the cache
html = panel.render_html(parent_context)
with self.assertNumQueries(5):
# Rendering RecentEditsPanel should not generate N+1 queries -
# i.e. any number less than 6 would be reasonable here
html = panel.render_html(parent_context)
# check that the panel is still actually returning results
self.assertIn("Ameristralia Day", html)
soup = self.get_soup(html)
self.assertEqual(len(soup.select('svg use[href="#icon-lock"]')), 2)
expected_statuses = [
"live + draft",
"live + scheduled",
"live + scheduled",
"in moderation",
"in moderation",
]
statuses = [
"".join(e.find_all(string=True, recursive=False)).strip()
for e in soup.select(".w-status")
]
self.assertEqual(statuses, expected_statuses)
class TestLockedPagesQueryCount(WagtailTestUtils, TestCase):
fixtures = ["test.json"]
def setUp(self):
self.bob = self.create_superuser(username="bob", password="password")
self.dummy_request = get_dummy_request()
self.dummy_request.user = self.bob
pages = Page.objects.filter(pk__in=[9, 12, 13]).order_by("pk")
for i, page in enumerate(pages):
page.locked = True
page.locked_by = self.bob
page.locked_at = timezone.now() + timezone.timedelta(hours=i)
page.save()
def test_panel_query_count(self):
panel = LockedPagesPanel()
parent_context = {"request": self.dummy_request, "csrf_token": "dummy"}
# Warm up the cache
html = panel.render_html(parent_context)
with self.assertNumQueries(1):
html = panel.render_html(parent_context)
soup = self.get_soup(html)
# Should be sorted descending by locked_at
expected_titles = [
"Saint Patrick (single event)",
"Steal underpants",
"Ameristralia Day",
]
titles = [e.get_text(strip=True) for e in soup.select(".title-wrapper a")]
self.assertEqual(titles, expected_titles)
class UserObjectsInWorkflowModerationQueryCount(WagtailTestUtils, TestCase):
fixtures = ["test.json"]
def setUp(self):
self.superuser = self.create_superuser(username="admin", password="password")
self.bob = self.create_user(username="bob", password="password")
self.someone_else = self.create_user(
username="someoneelse", password="password"
)
editors = Group.objects.get(name="Editors")
editors.user_set.add(self.bob, self.someone_else)
workflow = Workflow.objects.first()
WorkflowContentType.objects.create(
workflow=workflow,
content_type=ContentType.objects.get_for_model(FullFeaturedSnippet),
)
GroupPagePermission.objects.create(
group=editors, page=Page.get_first_root_node(), permission_type="change"
)
editors.permissions.add(
Permission.objects.get(codename="change_fullfeaturedsnippet")
)
# Pages owned by bob, but workflow started by someone else
Page.objects.filter(id__in=[9, 12]).update(owner=self.bob)
for page in Page.objects.filter(id__in=[9, 12]).specific():
page.save_revision()
workflow.start(page, self.someone_else)
# Lock it to test the lock indicator
page.locked = True
page.locked_by = self.superuser
page.locked_at = timezone.now()
page.save()
# Page workflow started by bob
for page in Page.objects.filter(id__in=[4, 13]).specific():
page.save_revision()
workflow.start(page, self.bob)
# Snippet workflow started by bob
for i in range(1, 3):
obj = FullFeaturedSnippet.objects.create(text=f"Some obj {i}")
obj.save_revision()
workflow.start(obj, self.bob)
self.dummy_request = get_dummy_request()
self.dummy_request.user = self.bob
def test_panel_query_count(self):
panel = UserObjectsInWorkflowModerationPanel()
parent_context = {"request": self.dummy_request}
# Warm up the cache
html = panel.render_html(parent_context)
with self.assertNumQueries(4):
html = panel.render_html(parent_context)
soup = self.get_soup(html)
self.assertEqual(len(soup.select('svg use[href="#icon-lock"]')), 2)
expected_titles = [
"Some obj 2",
"Some obj 1",
"Saint Patrick (single event)",
"Christmas",
"Steal underpants",
"Ameristralia Day",
]
titles = [e.get_text(strip=True) for e in soup.select(".title-wrapper a")]
self.assertEqual(titles, expected_titles)
class WorkflowObjectsToModerateQueryCount(WagtailTestUtils, TestCase):
fixtures = ["test.json"]
def setUp(self):
self.superuser = self.create_superuser(username="admin", password="password")
self.bob = self.create_user(username="bob", password="password")
self.moderator = self.create_user(username="moderator", password="password")
editors = Group.objects.get(name="Editors")
moderators = Group.objects.get(name="Moderators")
editors.user_set.add(self.bob)
moderators.user_set.add(self.moderator)
root = Page.get_first_root_node()
GroupPagePermission.objects.create(
group=editors, page=root, permission_type="change"
)
GroupPagePermission.objects.create(
group=moderators, page=root, permission_type="change"
)
GroupPagePermission.objects.create(
group=moderators, page=root, permission_type="publish"
)
editors.permissions.add(
Permission.objects.get(codename="change_fullfeaturedsnippet")
)
moderators.permissions.add(
*Permission.objects.filter(
codename__in=[
"change_fullfeaturedsnippet",
"publish_fullfeaturedsnippet",
]
),
)
workflow = Workflow.objects.first()
WorkflowContentType.objects.create(
workflow=workflow,
content_type=ContentType.objects.get_for_model(FullFeaturedSnippet),
)
# Pages workflow started by bob and locked by moderator
for page in Page.objects.filter(id__in=[9, 12]).specific():
page.save_revision()
workflow.start(page, self.bob)
# Lock it to test the lock indicator
page.locked = True
page.locked_by = self.moderator
page.locked_at = timezone.now()
page.save()
# Page workflow started by bob
for page in Page.objects.filter(id__in=[4, 13]).specific():
page.save_revision()
workflow.start(page, self.bob)
# Snippet workflow started by bob
for i in range(1, 3):
obj = FullFeaturedSnippet.objects.create(text=f"Some obj {i}")
obj.save_revision()
workflow.start(obj, self.bob)
self.dummy_request = get_dummy_request()
self.dummy_request.user = self.moderator
def test_panel_query_count(self):
panel = WorkflowObjectsToModeratePanel()
parent_context = {"request": self.dummy_request, "csrf_token": "dummy"}
# Warm up the cache
html = panel.render_html(parent_context)
with self.assertNumQueries(13):
html = panel.render_html(parent_context)
soup = self.get_soup(html)
self.assertEqual(len(soup.select('svg use[href="#icon-lock"]')), 2)
expected_titles = [
"Some obj 2",
"Some obj 1",
"Saint Patrick (single event)",
"Christmas",
"Steal underpants",
"Ameristralia Day",
]
titles = [e.get_text(strip=True) for e in soup.select(".title-wrapper a")]
self.assertEqual(titles, expected_titles)