kopia lustrzana https://github.com/wagtail/wagtail
Limit the explorer breadcrumb to the pages the user has explore permission over
Refactor of #3133pull/3197/head
rodzic
2a76a30e7b
commit
e953cb36dc
|
@ -5,17 +5,22 @@ from django.db.models import Q
|
||||||
from wagtail.wagtailcore.models import Page
|
from wagtail.wagtailcore.models import Page
|
||||||
|
|
||||||
|
|
||||||
def get_navigation_menu_items(user):
|
def get_pages_with_direct_explore_permission(user):
|
||||||
# Get all pages that the user has direct add/edit/publish/lock permission on
|
# Get all pages that the user has direct add/edit/publish/lock permission on
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
# superuser has implicit permission on the root node
|
# superuser has implicit permission on the root node
|
||||||
pages_with_direct_permission = Page.objects.filter(depth=1)
|
return Page.objects.filter(depth=1)
|
||||||
else:
|
else:
|
||||||
pages_with_direct_permission = Page.objects.filter(
|
return Page.objects.filter(
|
||||||
group_permissions__group__in=user.groups.all(),
|
group_permissions__group__in=user.groups.all(),
|
||||||
group_permissions__permission_type__in=['add', 'edit', 'publish', 'lock']
|
group_permissions__permission_type__in=['add', 'edit', 'publish', 'lock']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_navigation_menu_items(user):
|
||||||
|
# Get all pages that the user has direct add/edit/publish/lock permission on
|
||||||
|
pages_with_direct_permission = get_pages_with_direct_explore_permission(user)
|
||||||
|
|
||||||
if not(pages_with_direct_permission):
|
if not(pages_with_direct_permission):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
<ul class="breadcrumb">
|
<ul class="breadcrumb">
|
||||||
{% for page in pages %}
|
{% for page in pages %}
|
||||||
{% if page.is_root %}
|
{% if forloop.first %}
|
||||||
<li class="home"><a href="{% url 'wagtailadmin_explore_root' %}" class="icon icon-home text-replace">{% trans 'Home' %}</a></li>
|
{# first item in breadcrumb displays as a 'home' icon in place of the title #}
|
||||||
|
<li class="home"><a href="{% if page.is_root %}{% url 'wagtailadmin_explore_root' %}{% else %}{% url 'wagtailadmin_explore' page.id %}{% endif %}" class="icon icon-home text-replace">{% trans 'Home' %}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="{% url 'wagtailadmin_explore' page.id %}">{{ page.get_admin_display_title }}</a></li>
|
<li><a href="{% url 'wagtailadmin_explore' page.id %}">{{ page.get_admin_display_title }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django import template
|
from django import template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -14,10 +13,11 @@ from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from wagtail.utils.pagination import DEFAULT_PAGE_KEY, replace_page_in_query
|
from wagtail.utils.pagination import DEFAULT_PAGE_KEY, replace_page_in_query
|
||||||
from wagtail.wagtailadmin.menu import admin_menu
|
from wagtail.wagtailadmin.menu import admin_menu
|
||||||
from wagtail.wagtailadmin.navigation import get_navigation_menu_items
|
from wagtail.wagtailadmin.navigation import (
|
||||||
|
get_navigation_menu_items, get_pages_with_direct_explore_permission)
|
||||||
from wagtail.wagtailadmin.search import admin_search_areas
|
from wagtail.wagtailadmin.search import admin_search_areas
|
||||||
from wagtail.wagtailcore import hooks
|
from wagtail.wagtailcore import hooks
|
||||||
from wagtail.wagtailcore.models import PageViewRestriction, UserPagePermissionsProxy
|
from wagtail.wagtailcore.models import Page, PageViewRestriction, UserPagePermissionsProxy
|
||||||
from wagtail.wagtailcore.utils import cautious_slugify as _cautious_slugify
|
from wagtail.wagtailcore.utils import cautious_slugify as _cautious_slugify
|
||||||
from wagtail.wagtailcore.utils import camelcase_to_underscore, escape_script
|
from wagtail.wagtailcore.utils import camelcase_to_underscore, escape_script
|
||||||
|
|
||||||
|
@ -55,10 +55,21 @@ def main_nav(context):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@register.inclusion_tag('wagtailadmin/shared/breadcrumb.html')
|
@register.inclusion_tag('wagtailadmin/shared/breadcrumb.html', takes_context=True)
|
||||||
def explorer_breadcrumb(page, include_self=False):
|
def explorer_breadcrumb(context, page, include_self=False):
|
||||||
|
user = context['request'].user
|
||||||
|
|
||||||
|
# find the closest common ancestor of the pages that this user has direct explore permission
|
||||||
|
# (i.e. add/edit/publish/lock) over; this will be the root of the breadcrumb
|
||||||
|
try:
|
||||||
|
cca = get_pages_with_direct_explore_permission(user).first_common_ancestor(
|
||||||
|
include_self=True, strict=True
|
||||||
|
)
|
||||||
|
except Page.DoesNotExist:
|
||||||
|
return {'pages': Page.objects.none()}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'pages': page.get_ancestors(inclusive=include_self)
|
'pages': page.get_ancestors(inclusive=include_self).descendant_of(cca, inclusive=True)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -331,6 +331,83 @@ class TestPageExplorerSignposting(TestCase, WagtailTestUtils):
|
||||||
self.assertNotContains(response, "Pages created here will not be accessible")
|
self.assertNotContains(response, "Pages created here will not be accessible")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestExplorablePageVisibility(TestCase, WagtailTestUtils):
|
||||||
|
"""
|
||||||
|
Test the way that the Explorable Pages functionality manifests within the Explorer.
|
||||||
|
This is isolated in its own test case because it requires a custom page tree and custom set of
|
||||||
|
users and groups.
|
||||||
|
The fixture sets up this page tree:
|
||||||
|
========================================================
|
||||||
|
ID Site Path
|
||||||
|
========================================================
|
||||||
|
1 /
|
||||||
|
2 testserver /home/
|
||||||
|
3 testserver /home/about-us/
|
||||||
|
4 example.com /example-home/
|
||||||
|
5 example.com /example-home/content/
|
||||||
|
6 example.com /example-home/content/page-1/
|
||||||
|
7 example.com /example-home/content/page-2/
|
||||||
|
9 example.com /example-home/content/page-2/child-1
|
||||||
|
8 example.com /example-home/other-content/
|
||||||
|
10 example2.com /home-2/
|
||||||
|
========================================================
|
||||||
|
Group 1 has explore and choose permissions rooted at testserver's homepage.
|
||||||
|
Group 2 has explore and choose permissions rooted at example.com's page-1.
|
||||||
|
Group 3 has explore and choose permissions rooted at example.com's other-content.
|
||||||
|
User "jane" is in Group 1.
|
||||||
|
User "bob" is in Group 2.
|
||||||
|
User "sam" is in Groups 1 and 2.
|
||||||
|
User "josh" is in Groups 2 and 3.
|
||||||
|
User "mary" is is no Groups, but she has the "access wagtail admin" permission.
|
||||||
|
User "superman" is an admin.
|
||||||
|
"""
|
||||||
|
|
||||||
|
fixtures = ['test_explorable_pages.json']
|
||||||
|
|
||||||
|
# Integration tests adapted from @coredumperror
|
||||||
|
|
||||||
|
def test_admin_can_explore_every_page(self):
|
||||||
|
self.assertTrue(self.client.login(username='superman', password='password'))
|
||||||
|
for page in Page.objects.all():
|
||||||
|
response = self.client.get(reverse('wagtailadmin_explore', args=[page.pk]))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_admin_sees_root_page_as_explorer_root(self):
|
||||||
|
self.assertTrue(self.client.login(username='superman', password='password'))
|
||||||
|
response = self.client.get(reverse('wagtailadmin_explore_root'))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
# Administrator should see the full list of children of the Root page.
|
||||||
|
self.assertContains(response, "Welcome to testserver!")
|
||||||
|
self.assertContains(response, "Welcome to example.com!")
|
||||||
|
|
||||||
|
def test_admin_sees_breadcrumbs_up_to_root_page(self):
|
||||||
|
self.assertTrue(self.client.login(username='superman', password='password'))
|
||||||
|
response = self.client.get(reverse('wagtailadmin_explore', args=[6]))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertInHTML(
|
||||||
|
"""<li class="home"><a href="/admin/pages/" class="icon icon-home text-replace">Home</a></li>""",
|
||||||
|
str(response.content)
|
||||||
|
)
|
||||||
|
self.assertInHTML("""<li><a href="/admin/pages/4/">Welcome to example.com!</a></li>""", str(response.content))
|
||||||
|
self.assertInHTML("""<li><a href="/admin/pages/5/">Content</a></li>""", str(response.content))
|
||||||
|
|
||||||
|
def test_nonadmin_sees_breadcrumbs_up_to_cca(self):
|
||||||
|
self.assertTrue(self.client.login(username='josh', password='password'))
|
||||||
|
response = self.client.get(reverse('wagtailadmin_explore', args=[6]))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
# While at "Page 1", Josh should see the breadcrumbs leading only as far back as the example.com homepage,
|
||||||
|
# since it's his Closest Common Ancestor.
|
||||||
|
self.assertInHTML(
|
||||||
|
"""<li class="home"><a href="/admin/pages/4/" class="icon icon-home text-replace">Home</a></li>""",
|
||||||
|
str(response.content)
|
||||||
|
)
|
||||||
|
self.assertInHTML("""<li><a href="/admin/pages/5/">Content</a></li>""", str(response.content))
|
||||||
|
# The page title shouldn't appear because it's the "home" breadcrumb.
|
||||||
|
self.assertNotContains(response, "Welcome to example.com!")
|
||||||
|
|
||||||
|
|
||||||
class TestPageCreation(TestCase, WagtailTestUtils):
|
class TestPageCreation(TestCase, WagtailTestUtils):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Find root page
|
# Find root page
|
||||||
|
|
Ładowanie…
Reference in New Issue