Skip to content

ISSUE 1073: Menu Rendering Permission Fix and Testcases #1106

Merged
merged 22 commits into from Jan 9, 2012
+1,358 −91
View
145 cms/menu.py
@@ -2,90 +2,156 @@
from collections import defaultdict
from cms.apphook_pool import apphook_pool
from cms.models.moderatormodels import (ACCESS_DESCENDANTS,
- ACCESS_PAGE_AND_DESCENDANTS, ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN)
+ ACCESS_PAGE_AND_DESCENDANTS, ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE)
from cms.models.permissionmodels import PagePermission, GlobalPagePermission
from cms.models.titlemodels import Title
from cms.utils import get_language_from_request
from cms.utils.i18n import get_fallback_languages
from cms.utils.moderator import get_page_queryset, get_title_queryset
from cms.utils.plugins import current_site
-from django.conf import settings
-from django.contrib.sites.models import Site
-from django.db.models.query_utils import Q
from menus.base import Menu, NavigationNode, Modifier
from menus.menu_pool import menu_pool
+from django.conf import settings
+from django.contrib.sites.models import Site
+from django.db.models.query_utils import Q
+from django.contrib.auth.models import Permission
def get_visible_pages(request, pages, site=None):
- # This code is basically a many-pages-at-once version of
- # Page.has_view_permission, check there to see wtf is going on here.
- if request.user.is_staff and settings.CMS_PUBLIC_FOR in ('staff', 'all'):
- return [page.pk for page in pages]
- page_ids = []
+ """
+ This code is basically a many-pages-at-once version of
+ Page.has_view_permission.
+ pages contains all published pages
+ check if there is ANY restriction
+ that needs a permission page visibility calculation
+ """
+ is_setting_public_all = settings.CMS_PUBLIC_FOR == 'all'
+ is_setting_public_staff = settings.CMS_PUBLIC_FOR == 'staff'
+ is_auth_user = request.user.is_authenticated()
+ visible_page_ids = []
+ restricted_pages = defaultdict(list)
pages_perms_q = Q()
+
for page in pages:
+ # taken from for_page as multiple at once version
page_q = Q(page__tree_id=page.tree_id) & (
Q(page=page)
| (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
| (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
)
@kezabelle
kezabelle added a note Jan 3, 2012

Did you end up adding an equivalent test for this equivalent of the alleged problem in #1113? I don't know if this query would be affected by that issue, but given the code is the same I'm just asking for the sake of completeness, and there's so many tests I can't see the wood for the trees.

@FrankBie2
FrankBie2 added a note Jan 3, 2012

I have not encountered the problem, during all test variations, but have not added a specific testcase covering it.

@FrankBie2
FrankBie2 added a note Jan 3, 2012

The django cms menu is a complex beast, if permissions is turned on.

cms_public_for: staff, all = 2 possibilities (a)
authenticated, anonymour user = 2 possibilities (b)
user_view_perm to a page, yes/no = 2 possibilities (c)
and the grant_on options page, child, page+child, descendant, descendant+page = 5 possibilities (d)
abc*d tests to cover some basic settings.

@FrankBie2
FrankBie2 added a note Jan 4, 2012

Just added a test for #1113

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
pages_perms_q |= page_q
+
+
pages_perms_q &= Q(can_view=True)
page_permissions = PagePermission.objects.filter(pages_perms_q).select_related('page', 'group__users')
-
- restricted_pages = defaultdict(list)
+
for perm in page_permissions:
- restricted_pages[perm.page.pk].append(perm)
+ # collect the pages that are affected by permissions
+ if perm is not None and perm not in restricted_pages[perm.page.pk]:
+ # affective restricted pages gathering
+ # using mptt functions
+ # add the page with the perm itself
+ if perm.grant_on in [ACCESS_PAGE, ACCESS_PAGE_AND_CHILDREN ,ACCESS_PAGE_AND_DESCENDANTS]:
+ restricted_pages[perm.page.pk].append(perm)
+ # add children
+ if perm.grant_on in [ACCESS_CHILDREN, ACCESS_PAGE_AND_CHILDREN]:
+ child_ids = perm.page.get_children().values_list('id', flat=True)
+ for id in child_ids:
+ restricted_pages[id].append(perm)
+ # add descendants
+ elif perm.grant_on in [ACCESS_DESCENDANTS, ACCESS_PAGE_AND_DESCENDANTS]:
+ child_ids = perm.page.get_descendants().values_list('id', flat=True)
+ for id in child_ids:
+ restricted_pages[id].append(perm)
+ # anonymous
+ # no restriction applied at all
+ if (not is_auth_user and
+ is_setting_public_all and
+ not restricted_pages):
+ return [page.pk for page in pages]
+
if site is None:
site = current_site(request)
- if request.user.is_authenticated():
- #return self.filter(Q(user=user) | Q(group__user=user))
+ # authenticated user and global permission
+ if is_auth_user:
global_page_perm_q = Q(
Q(user=request.user) | Q(group__user=request.user)
) & Q(can_view=True) & Q(Q(sites__in=[site.pk]) | Q(sites__isnull=True))
global_view_perms = GlobalPagePermission.objects.filter(global_page_perm_q).exists()
+
+ #no page perms edgcase - all visible
+ if ((is_setting_public_all or (
+ is_setting_public_staff and request.user.is_staff))and
+ not restricted_pages and
+ not global_view_perms):
+ return [page.pk for page in pages]
+ #no page perms edgcase - none visible
+ elif (is_setting_public_staff and
+ not request.user.is_staff and
+ not restricted_pages and
+ not global_view_perms):
+ return []
+
def has_global_perm():
if has_global_perm.cache < 0:
has_global_perm.cache = 1 if request.user.has_perm('cms.view_page') else 0
return bool(has_global_perm.cache)
has_global_perm.cache = -1
- def has_permission(page):
+ def has_permission_membership(page):
"""
- PagePermission tests
+ PagePermission user group membership tests
"""
- for perm in restricted_pages[page.pk]:
- if perm.user_id == request.user.pk:
- return True
- for perm in restricted_pages[page.pk]:
+ user_pk = request.user.pk
+ page_pk = page.pk
+ has_perm = False
+ for perm in restricted_pages[page_pk]:
+ if perm.user_id == user_pk:
+ has_perm = True
if not perm.group_id:
continue
- if request.user.pk in perm.group.user_set.values_list('id', flat=True):
- return True
- return False
+ group_user_ids = perm.group.user_set.values_list('pk', flat=True)
+ if user_pk in group_user_ids:
+ has_perm = True
+ return has_perm
for page in pages:
+ to_add = False
+ # default to false, showing a restricted page is bad
+ # explicitly check all the conditions
+ # of settings and permissions
is_restricted = page.pk in restricted_pages
-
- if request.user.is_authenticated():
+ # restricted_pages contains as key any page.pk that is
+ # affected by a permission grant_on
+ if is_auth_user:
# a global permission was given to the request's user
if global_view_perms:
- page_ids.append(page.pk)
- # authenticated user, no restriction and public for all
- elif settings.CMS_PUBLIC_FOR == 'all':
- page_ids.append(page.pk)
- elif has_permission(page):
- page_ids.append(page.pk)
+ to_add = True
+ # setting based handling of unrestricted pages
+ elif not is_restricted and (
+ is_setting_public_all or (
+ is_setting_public_staff and request.user.is_staff)
+ ):
+ # authenticated user, no restriction and public for all
+ # or
+ # authenticated staff user, no restriction and public for staff
+ to_add = True
+ # check group and user memberships to restricted pages
+ elif is_restricted and has_permission_membership(page):
+ to_add = True
elif has_global_perm():
- page_ids.append(page.pk)
- elif not is_restricted and settings.CMS_PUBLIC_FOR == 'all':
- # anonymous user, no restriction saved in database
- page_ids.append(page.pk)
- return page_ids
+ to_add = True
+ # anonymous user, no restriction
+ elif not is_restricted and is_setting_public_all:
+ to_add = True
+ # store it
+ if to_add:
+ visible_page_ids.append(page.pk)
+ return visible_page_ids
def page_to_node(page, home, cut):
'''
@@ -178,7 +244,6 @@ def get_nodes(self, request):
# cache view perms
visible_pages = get_visible_pages(request, pages, site)
-
for page in pages:
# Pages are ordered by tree_id, therefore the first page is the root
# of the page tree (a.k.a "home")
@@ -190,8 +255,6 @@ def get_nodes(self, request):
page.home_pk_cache = home.pk
if first and page.pk != home.pk:
home_cut = True
- elif not settings.CMS_PUBLIC_FOR == 'all':
- continue
if (page.parent_id == home.pk or page.parent_id in home_children) and home_cut:
home_children.append(page.pk)
if (page.pk == home.pk and home.in_navigation) or page.pk != home.pk:
@@ -295,7 +358,7 @@ class SoftRootCutter(Modifier):
usually don’t want to present site visitors with deep menus of nested
items.
- For example, you’re on the page Introduction to Bleeding, so the menu
+ For example, you’re on the page -Introduction to Bleeding-?, so the menu
might look like this:
School of Medicine
@@ -326,7 +389,7 @@ class SoftRootCutter(Modifier):
which is frankly overwhelming.
- By making Department of Mediaeval Surgery a soft root, the menu
+ By making -Department of Mediaeval Surgery-? a soft root, the menu
becomes much more manageable:
Department of Mediaeval Surgery
View
20 cms/models/managers.py
@@ -343,13 +343,23 @@ def for_page(self, page):
"""
from cms.models import ACCESS_DESCENDANTS, ACCESS_CHILDREN,\
ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE_AND_DESCENDANTS
+ # code taken from
+ # https://github.com/divio/django-cms/issues/1113#issuecomment-3376790
+ q_tree = Q(page__tree_id=page.tree_id)
+ q_page = Q(page=page)
- q = Q(page__tree_id=page.tree_id) & (
- Q(page=page)
- | (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
- | (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
- )
+ # NOTE: '... or 0' is used for test cases,
+ # if the page is not saved through mptt
+ left_right = {
+ 'page__%s__lte' % page._meta.left_attr: getattr(page, page._meta.left_attr) or 0,
+ 'page__%s__gte' % page._meta.right_attr: getattr(page, page._meta.right_attr) or 0,
+ }
+ q_parents = Q(**left_right)
+ q_desc = (Q(page__level__lt=page.level) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS)))
+ q_kids = (Q(page__level=page.level - 1) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN)))
+ q = q_tree & q_parents & (q_page | q_desc | q_kids)
return self.filter(q).order_by('page__level')
+
class PagePermissionsPermissionManager(models.Manager):
"""Page permissions permission manager.
View
30 cms/models/pagemodel.py
@@ -680,31 +680,39 @@ def get_template_name(self):
def has_view_permission(self, request):
from cms.models.permissionmodels import PagePermission, GlobalPagePermission
from cms.utils.plugins import current_site
- # staff is allowed to see everything
- if request.user.is_staff and settings.CMS_PUBLIC_FOR in ('staff', 'all'):
- return True
-
+
if not self.publisher_is_draft and self.publisher_public:
return self.publisher_public.has_view_permission(request)
# does any restriction exist?
- # direct
# inherited and direct
- is_restricted = PagePermission.objects.for_page(self).filter(can_view=True).exists()
-
+ is_restricted = PagePermission.objects.for_page(page=self).filter(can_view=True).exists()
if request.user.is_authenticated():
site = current_site(request)
global_perms_q = Q(can_view=True) & Q(
Q(sites__in=[site]) | Q(sites__isnull=True)
)
global_view_perms = GlobalPagePermission.objects.with_user(
request.user).filter(global_perms_q).exists()
+
# a global permission was given to the request's user
if global_view_perms:
return True
- # authenticated user, no restriction and public for all
- if (not is_restricted and not global_view_perms and
- settings.CMS_PUBLIC_FOR == 'all'):
- return True
+
+ elif not is_restricted:
+ if ((settings.CMS_PUBLIC_FOR == 'all') or
+ (settings.CMS_PUBLIC_FOR == 'staff' and
+ request.user.is_staff)):
+ return True
+
+ # a restricted page and an authenticated user
+ elif is_restricted:
+ opts = self._meta
+ codename = '%s.view_%s' % (opts.app_label, opts.object_name.lower())
+ user_perm = request.user.has_perm(codename)
+ generic_perm = self.has_generic_permission(request, "view")
+ return (user_perm or generic_perm)
+
+
else:
#anonymous user
if is_restricted or not settings.CMS_PUBLIC_FOR == 'all':
View
4 cms/tests/__init__.py
@@ -27,4 +27,6 @@
from cms.tests.toolbar import *
from cms.tests.urlutils import *
from cms.tests.views import *
-from cms.tests.management import *
+from cms.tests.management import *
+from cms.tests.menu_page_viewperm import *
+from cms.tests.menu_page_viewperm_staff import *
View
43 cms/tests/menu.py
@@ -10,14 +10,15 @@
from cms.test_utils.util.context_managers import (SettingsOverride,
LanguageOverride)
from cms.test_utils.util.mock import AttributeObject
+from menus.base import NavigationNode
+from menus.menu_pool import menu_pool, _build_nodes_inner_for_one_menu
+from menus.utils import mark_descendants, find_selected, cut_levels
+
from django.conf import settings
from django.contrib.auth.models import AnonymousUser, User, Permission, Group
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.template import Template, TemplateSyntaxError
-from menus.base import NavigationNode
-from menus.menu_pool import menu_pool, _build_nodes_inner_for_one_menu
-from menus.utils import mark_descendants, find_selected, cut_levels
class BaseMenuTest(SettingsOverrideTestCase):
@@ -762,6 +763,8 @@ def test_public_for_all_staff(self):
request.user.is_staff = True
page = Page()
page.pk = 1
+ page.level = 0
+ page.tree_id = 1
pages = [page]
result = get_visible_pages(request, pages)
self.assertEqual(result, [1])
@@ -771,8 +774,14 @@ def test_public_for_all_staff_assert_num_queries(self):
request.user.is_staff = True
page = Page()
page.pk = 1
+ page.level = 0
+ page.tree_id = 1
pages = [page]
- with self.assertNumQueries(0):
+ with self.assertNumQueries(1):
+ """
+ The queries are:
+ PagePermission count query
+ """
get_visible_pages(request, pages)
def test_public_for_all(self):
@@ -834,7 +843,10 @@ def test_unauthed_num_queries(self):
def test_authed_basic_perm(self):
with SettingsOverride(CMS_PUBLIC_FOR='staff'):
- user = User.objects.create_user('user', 'user@domain.com', 'user')
+ user = User()
+ user.username="test"
+ user.is_staff = True
+ user.save()
user.user_permissions.add(Permission.objects.get(codename='view_page'))
request = self.get_request(user)
page = Page()
@@ -849,21 +861,22 @@ def test_authed_basic_perm_num_queries(self):
site = Site()
site.pk = 1
with SettingsOverride(CMS_PUBLIC_FOR='staff'):
- user = User.objects.create_user('user', 'user@domain.com', 'user')
+ user = User()
+ user.username="test"
+ user.is_staff = True
+ user.save()
user.user_permissions.add(Permission.objects.get(codename='view_page'))
request = self.get_request(user)
page = Page()
page.pk = 1
page.level = 0
page.tree_id = 1
pages = [page]
- with self.assertNumQueries(4):
+ with self.assertNumQueries(2):
@ojii
ojii added a note Dec 25, 2011

nice

@chrisglass
chrisglass added a note Jan 3, 2012

shiny :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
"""
The queries are:
- PagePermission query for affected pages
- GlobalpagePermission query for user
- Generic django permission lookup
- content type lookup by permission lookup
+ PagePermission count query
+ GlobalpagePermission count query
"""
get_visible_pages(request, pages, site)
@@ -890,13 +903,11 @@ def test_authed_no_access_num_queries(self):
page.level = 0
page.tree_id = 1
pages = [page]
- with self.assertNumQueries(4):
+ with self.assertNumQueries(2):
"""
The queries are:
- PagePermission query for affected pages
- GlobalpagePermission query for user
- Generic django permission lookup
- content type lookup by permission lookup
+ View Permission Calculation Query
+ globalpagepermissino calculation
"""
get_visible_pages(request, pages, site)
View
596 cms/tests/menu_page_viewperm.py
@@ -0,0 +1,596 @@
+# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
+from cms.api import create_page
+from cms.menu import CMSMenu, get_visible_pages
+from cms.models import Page
+from cms.models import ACCESS_DESCENDANTS, ACCESS_CHILDREN, ACCESS_PAGE
+from cms.models import ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE_AND_DESCENDANTS
+from cms.models.permissionmodels import GlobalPagePermission, PagePermission
+from cms.models.titlemodels import Title
+from cms.test_utils.testcases import SettingsOverrideTestCase
+
+from django.contrib.sites.models import Site
+from django.contrib.auth.models import AnonymousUser, User, Permission, Group
+from django.db.models import Q
+from django.test.client import Client
+
+
+class ViewPermissionTests(SettingsOverrideTestCase):
+ """
+ Test various combinations of view permissions pages and menus
+ Focus on the different grant types and inheritance options of grant on
+ Given the tree:
+
+ |- Page_a
+ |- Page_b
+ | |- Page_b_a
+ | |- Page_b_b
+ | | |- Page_b_b_a
+ | | | |- Page_b_b_a_a
+ | | |- Page_b_b_b
+ | | |- Page_b_b_c
+ | |- Page_b_c
+ | |- Page_b_d
+ | | |- Page_b_d_a
+ | | |- Page_b_d_b
+ | | |- Page_b_d_c
+ |- Page_c
+ |- Page_d
+ | |- Page_d_a
+ | |- Page_d_b
+ | |- Page_d_c
+ """
+ GROUPNAME_1 = 'group_b_ACCESS_PAGE_AND_CHILDREN'
+ GROUPNAME_2 = 'group_b_b_ACCESS_CHILDREN'
+ GROUPNAME_3 = 'group_b_ACCESS_PAGE_AND_DESCENDANTS'
+ GROUPNAME_4 = 'group_b_b_ACCESS_DESCENDANTS'
+ GROUPNAME_5 = 'group_d_ACCESS_PAGE'
+
+ def setUp(self):
+ self.site = Site()
+ self.site.pk = 1
+ super(ViewPermissionTests, self).setUp()
+
+ def tearDown(self):
+ super(ViewPermissionTests, self).tearDown()
+
+ def _setup_tree_pages(self):
+ stdkwargs = {
+ 'template': 'nav_playground.html',
+ 'language': 'en',
+ 'published': True,
+ 'in_navigation': True,
+ }
+ page_a = create_page("page_a", **stdkwargs) # first page slug is /
+ page_b = create_page("page_b", **stdkwargs)
+ page_c = create_page("page_c", **stdkwargs)
+ page_d = create_page("page_d", **stdkwargs)
+
+ page_b_a = create_page("page_b_a", parent=page_b, **stdkwargs)
+ page_b_b = create_page("page_b_b", parent=page_b, **stdkwargs)
+ page_b_b_a = create_page("page_b_b_a", parent=page_b_b, **stdkwargs)
+ page_b_b_b = create_page("page_b_b_b", parent=page_b_b, **stdkwargs)
+ page_b_b_c = create_page("page_b_b_c", parent=page_b_b, **stdkwargs)
+ page_b_b_a_a = create_page("page_b_b_a_a", parent=page_b_b_a, **stdkwargs)
+
+ page_b_c = create_page("page_b_c", parent=page_b, **stdkwargs)
+ page_b_d = create_page("page_b_d", parent=page_b, **stdkwargs)
+ page_b_d_a = create_page("page_b_d_a", parent=page_b_d, **stdkwargs)
+ page_b_d_b = create_page("page_b_d_b", parent=page_b_d, **stdkwargs)
+ page_b_d_c = create_page("page_b_d_c", parent=page_b_d, **stdkwargs)
+
+ page_d_a = create_page("page_d_a", parent=page_d, **stdkwargs)
+ page_d_b = create_page("page_d_b", parent=page_d, **stdkwargs)
+ page_d_c = create_page("page_d_c", parent=page_d, **stdkwargs)
+ page_d_d = create_page("page_d_d", parent=page_d, **stdkwargs)
+
+ return [page_a,
+ page_b,
+ page_b_a,
+ page_b_b,
+ page_b_b_a,
+ page_b_b_a_a,
+ page_b_b_b,
+ page_b_b_c,
+ page_b_c,
+ page_b_d,
+ page_b_d_a,
+ page_b_d_b,
+ page_b_d_c,
+ page_c,
+ page_d,
+ page_d_a,
+ page_d_b,
+ page_d_c,
+ page_d_d,
+ ]
+
+ def _setup_user_groups(self):
+ """
+ Setup a group for every grant on ACCESS TYPE
+ """
+ user = User.objects.create(username='user_1', email='user_1@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_1)
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_1_nostaff', email='user_1_nostaff@domain.com', is_active=True, is_staff=False)
+ user.set_password(user.username)
+ user.save()
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_2', email='user_2@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_2)
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_2_nostaff', email='user_2_nostaff@domain.com', is_active=True, is_staff=False)
+ user.set_password(user.username)
+ user.save()
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_3', email='user_3@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_3)
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_3_nostaff', email='user_3_nostaff@domain.com', is_active=True, is_staff=False)
+ user.set_password(user.username)
+ user.save()
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_4', email='user_4@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_4)
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_4_nostaff', email='user_4_nostaff@domain.com', is_active=True, is_staff=False)
+ user.set_password(user.username)
+ user.save()
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_5', email='user_5@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_5)
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_5_nostaff', email='user_5_nostaff@domain.com', is_active=True, is_staff=False)
+ user.set_password(user.username)
+ user.save()
+ group.user_set.add(user)
+ group.save()
+
+ user = User.objects.create(username='user_staff', email='user_staff@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+
+ self.assertEquals(11, User.objects.all().count())
+
+
+ def _setup_view_restrictions(self):
+ """
+ Setup a view restriction with every type of the grant_on ACCESS_*
+ 'group_b_ACCESS_PAGE_AND_CHILDREN'
+ 'group_b_b_ACCESS_CHILDREN'
+ 'group_b_ACCESS_PAGE_AND_DESCENDANTS'
+ 'group_b_b_ACCESS_DESCENDANTS'
+ 'group_d_ACCESS_PAGE'
+ """
+
+ page = Page.objects.get(title_set__title="page_b")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_1)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_PAGE_AND_CHILDREN)
+
+ page = Page.objects.get(title_set__title="page_b_b")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_2)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_CHILDREN)
+
+ page = Page.objects.get(title_set__title="page_b")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_3)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_PAGE_AND_DESCENDANTS)
+
+ page = Page.objects.get(title_set__title="page_b_b")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_4)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_DESCENDANTS)
+
+ page = Page.objects.get(title_set__title="page_d")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_5)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_PAGE)
+
+ self.assertEquals(5, PagePermission.objects.all().count())
+ self.assertEquals(0, GlobalPagePermission.objects.all().count())
+
+ def assertPageFound(self, url, client=None):
+ if not client:
+ client = Client()
+ response = client.get(url)
+ self.assertEquals(response.status_code, 200)
+
+ def assertPageNotFound(self, url, client=None):
+ if not client:
+ client = Client()
+ response = client.get(url)
+ self.assertEquals(response.status_code, 404)
+
+ def assertNodeMemberships(self, visible_page_ids, restricted_pages, public_page_ids):
+ """
+ test all visible page ids are either in_public and not in_restricted
+ or not in_public and in_restricted
+ """
+ for page_id in visible_page_ids:
+ in_restricted = False
+ in_public = False
+ if page_id in restricted_pages:
+ in_restricted = True
+ if page_id in public_page_ids:
+ in_public = True
+ self.assertTrue((in_public and not in_restricted) or
+ (not in_public and in_restricted),
+ msg="page_id %s in_public: %s, in_restricted: %s" % (page_id, in_public, in_restricted))
+
+ def assertGrantedVisibility(self, all_pages, expected_granted_pages, username=None):
+ """
+ helper function to check the expected_granted_pages are
+ not in the restricted_pages list and
+ all visible pages are in the expected_granted_pages
+ """
+ # log the user in if present
+ user = None
+ if username is not None:
+ user = User.objects.get(username__iexact=username)
+ request = self.get_request(user)
+ visible_page_ids = get_visible_pages(request, all_pages, self.site)
+ self.assertEquals(len(visible_page_ids), len(expected_granted_pages))
+ public_page_ids = Page.objects.filter(title_set__title__in=expected_granted_pages).values_list('id', flat=True)
+ restricted_pages = Page.objects.exclude(title_set__title__in=expected_granted_pages).values_list('id', flat=True)
+ self.assertNodeMemberships(visible_page_ids, restricted_pages, public_page_ids)
+
+ def get_request(self, user=None):
+ # see tests/menu.py line 753
+ attrs = {
+ 'user': user or AnonymousUser(),
+ 'REQUEST': {},
+ 'session': {},
+ }
+ return type('Request', (object,), attrs)
+
+
+class ViewPermissionComplexMenuAllNodesTests(ViewPermissionTests):
+ """
+ Test CMS_PUBLIC_FOR=all group access and menu nodes rendering
+ """
+ settings_overrides = {
+ 'CMS_MODERATOR': False,
+ 'CMS_PERMISSION': True,
+ 'CMS_PUBLIC_FOR': 'all',
+ }
+
+ def test_public_pages_anonymous_norestrictions(self):
+ """
+ All pages are visible to an anonymous user
+ """
+ all_pages = self._setup_tree_pages()
+ request = self.get_request()
+ visible_page_ids = get_visible_pages(request, all_pages, self.site)
+ self.assertEquals(len(all_pages), len(visible_page_ids))
+
+ def test_public_menu_anonymous_user(self):
+ """
+ Anonymous user should only see the pages in the rendered menu
+ that have no permissions assigned,directly or indirectly
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d'
+ ]
+ self.assertGrantedVisibility(all_pages, granted)
+
+ def test_menu_access_page_and_children_group_1(self):
+ """
+ simulate behaviour of group b member
+ group_b_ACCESS_PAGE_AND_CHILDREN to page_b
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_c',
+ #group_1
+ 'page_b', #page_id b has page_id and children restricted - group 1
+ 'page_b_a',
+ 'page_b_b', #page_id b_b children restricted - group 2
+ 'page_b_c',
+ 'page_b_d',
+ # not restricted
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d'
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_1')
+ client = Client()
+ login_ok = client.login(username='user_1', password='user_1')
+ self.assertEqual(login_ok , True)
+ url = "/en/page_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageFound(url, client)
+ # descendant
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ # group 5
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ # should be public as only page_d is restricted
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_menu_access_children_group_2(self):
+ """
+ simulate behaviour of group 2 member
+ GROUPNAME_2 = 'group_b_b_ACCESS_CHILDREN'
+ to page_b_b
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [
+ 'page_a',
+ 'page_c',
+ 'page_b_b_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ # not restricted
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_2')
+ client = Client()
+ login_ok = client.login(username='user_2', password='user_2')
+ self.assertEqual(login_ok , True)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_menu_access_page_and_descendants_group_3(self):
+ """
+ simulate behaviour of group 3 member
+ group_b_ACCESS_PAGE_AND_DESCENDANTS to page_b
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [ 'page_a',
+ 'page_b',
+ 'page_b_a',
+ 'page_b_b',
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_b_c',
+ 'page_b_d',
+ 'page_b_d_a',
+ 'page_b_d_b',
+ 'page_b_d_c',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_3')
+ client = Client()
+ login_ok = client.login(username='user_3', password='user_3')
+ self.assertEqual(login_ok , True)
+ url = "/en/page_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_d/page_b_d_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_menu_access_descendants_group_4(self):
+ """
+ simulate behaviour of group 4 member
+ group_b_b_ACCESS_DESCENDANTS to page_b_b
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [ 'page_a',
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_4')
+ client = Client()
+ login_ok = client.login(username='user_4', password='user_4')
+ self.assertTrue(login_ok)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_menu_access_page_group_5(self):
+ """
+ simulate behaviour of group b member
+ group_d_ACCESS_PAGE to page_d
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [ 'page_a',
+ 'page_c',
+ 'page_d',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_5')
+ client = Client()
+ login_ok = client.login(username='user_5', password='user_5')
+ self.assertTrue(login_ok)
+ # call /
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+
+class ViewPermissionTreeBugTests(ViewPermissionTests):
+ """Test issue 1113
+ https://github.com/divio/django-cms/issues/1113
+ Wrong view permission calculation in PagePermission.objects.for_page
+ grant_on=ACCESS_PAGE_AND_CHILDREN or ACCESS_PAGE_AND_DESCENDANTS to page 6
+ Test if this affects the menu entries and page visibility
+ """
+ settings_overrides = {
+ 'CMS_MODERATOR': False,
+ 'CMS_PERMISSION': True,
+ 'CMS_PUBLIC_FOR': 'all',
+ }
+ GROUPNAME_6 = 'group_6_ACCESS_PAGE'
+
+ def _setup_pages(self):
+ """
+ Tree Structure
+ |- Page_1
+ | |- Page_2
+ | |- Page_3
+ | |- Page_4 (false positive)
+ | |- Page_5
+ | | |- Page_6 (group 6 page access)
+ """
+ stdkwargs = {
+ 'template': 'nav_playground.html',
+ 'language': 'en',
+ 'published': True,
+ 'in_navigation': True,
+ }
+ page_1 = create_page("page_1", **stdkwargs) # first page slug is /
+ page_2 = create_page("page_2", parent=page_1, **stdkwargs)
+ page_3 = create_page("page_3", parent=page_2, **stdkwargs)
+ page_4 = create_page("page_4", parent=page_3, **stdkwargs)
+ page_5 = create_page("page_5", parent=page_1, **stdkwargs)
+ page_6 = create_page("page_6", parent=page_5, **stdkwargs)
+ return [page_1,
+ page_2,
+ page_3,
+ page_4,
+ page_5,
+ page_6,
+ ]
+
+ def _setup_user(self):
+ user = User.objects.create(username='user_6', email='user_6@domain.com', is_active=True, is_staff=True)
+ user.set_password(user.username)
+ user.save()
+ group = Group.objects.create(name=self.GROUPNAME_6)
+ group.user_set.add(user)
+ group.save()
+
+ def _setup_permviewbug(self):
+ """
+ Setup group_6_ACCESS_PAGE view restriction
+ """
+ page = Page.objects.get(title_set__title="page_6")
+ group = Group.objects.get(name__iexact=self.GROUPNAME_6)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_PAGE_AND_CHILDREN)
+ PagePermission.objects.create(can_view=True, group=group, page=page, grant_on=ACCESS_PAGE_AND_DESCENDANTS)
+
+ def test_pageforbug(self):
+ all_pages = self._setup_pages()
+ self._setup_user()
+ self._setup_permviewbug()
+ for page in all_pages:
+ perm = PagePermission.objects.for_page(page=page)
+ # only page_6 has a permission assigned
+ if page.get_title() == 'page_6':
+ self.assertEquals(len(perm), 2)
+ else:
+ msg="Permission wrong at page %s" % (page.get_title())
+ self.assertEquals(len(perm), 0,msg)
+ granted = [ 'page_1',
+ 'page_2',
+ 'page_3',
+ 'page_4',
+ 'page_5',
+ ]
+ # anonymous sees page_6 not
+ self.assertGrantedVisibility(all_pages, granted)
+ url = "/en/page_2/page_3/page_4/"
+ self.assertPageFound(url)
+ url = "/en/page_5/"
+ self.assertPageFound(url)
+ url = "/en/page_5/page_6/"
+ self.assertPageNotFound(url)
+ # group member
+ granted = [ 'page_1',
+ 'page_2',
+ 'page_3',
+ 'page_4',
+ 'page_5',
+ 'page_6',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_6')
+ client = Client()
+ login_ok = client.login(username='user_6', password='user_6')
+ self.assertTrue(login_ok)
+ url = "/en/page_2/page_3/page_4/"
+ self.assertPageFound(url, client)
+ url = "/en/page_5/page_6/"
+ self.assertPageFound(url, client)
+
+
View
524 cms/tests/menu_page_viewperm_staff.py
@@ -0,0 +1,524 @@
+# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
+from cms.tests.menu_page_viewperm import ViewPermissionTests
+from cms.models import Page
+
+from django.contrib.sites.models import Site
+from django.contrib.auth.models import User
+from django.test.client import Client
+
+
+class ViewPermissionComplexMenuStaffNodeTests(ViewPermissionTests):
+ """
+ Test CMS_PUBLIC_FOR=staff group access and menu nodes rendering
+ """
+ settings_overrides = {
+ 'CMS_MODERATOR': False,
+ 'CMS_PERMISSION': True,
+ 'CMS_PUBLIC_FOR': 'staff',
+ }
+
+ def test_public_pages_anonymous_norestrictions(self):
+ """
+ All pages are INVISIBLE to an anonymous user
+ """
+ all_pages = self._setup_tree_pages()
+ granted = []
+ self.assertGrantedVisibility(all_pages, granted)
+
+ def test_public_menu_anonymous_user(self):
+ """
+ Anonymous sees nothing, as he is no staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = []
+ self.assertGrantedVisibility(all_pages, granted)
+
+ def test_node_staff_access_page_and_children_group_1(self):
+ """
+ simulate behaviour of group b member
+ group_b_ACCESS_PAGE_AND_CHILDREN to page_b
+ staff user
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_b',
+ 'page_b_a',
+ 'page_b_b',
+ 'page_b_c',
+ 'page_b_d',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_1')
+ # user 1 is member of group_b_access_page_and_children
+ client = Client()
+ login_ok = client.login(username='user_1', password='user_1')
+ self.assertTrue(login_ok)
+ self.assertTrue('_auth_user_id' in client.session)
+ login_user_id = client.session.get('_auth_user_id')
+ user = User.objects.get(username='user_1')
+ self.assertEquals(login_user_id, user.id)
+ url = self.get_pages_root()
+ response = client.get(url)
+ self.assertEqual(response.status_code, 200)
+ self.assertEquals(response.context['request'].user.is_authenticated(), True)
+ self.assertEquals(response.context['request'].user.is_staff, True)
+ # call /
+ url = "/en/page_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_node_staff_access_page_and_children_group_1_no_staff(self):
+ """
+ simulate behaviour of group b member
+ group_b_ACCESS_PAGE_AND_CHILDREN to page_b
+ no staff user
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [
+ 'page_b',
+ 'page_b_a',
+ 'page_b_b',
+ 'page_b_c',
+ 'page_b_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_1_nostaff')
+ client = Client()
+ login_ok = client.login(username='user_1_nostaff', password='user_1_nostaff')
+ self.assertTrue(login_ok)
+ self.assertTrue('_auth_user_id' in client.session)
+ login_user_id = client.session.get('_auth_user_id')
+ user = User.objects.get(username='user_1_nostaff')
+ self.assertEquals(login_user_id, user.id)
+ # login worked
+ url = '/en/page_b/'
+ response = client.get(url)
+ self.assertEqual(response.status_code, 200)
+ self.assertEquals(response.context['request'].user.is_authenticated(), True)
+ self.assertEquals(response.context['request'].user.is_staff, False)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageNotFound(url, client)
+
+ def test_node_staff_access_children_group_2(self):
+ """
+ simulate behaviour of group 2 member
+ GROUPNAME_2 = 'group_b_b_ACCESS_CHILDREN'
+ to page_b_b and user is staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_b_b_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_2')
+ client = Client()
+ login_ok = client.login(username='user_2', password='user_2')
+ self.assertTrue(login_ok)
+ self.assertTrue('_auth_user_id' in client.session)
+ login_user_id = client.session.get('_auth_user_id')
+ user = User.objects.get(username='user_2')
+ self.assertEquals(login_user_id, user.id)
+ url = '/en/page_c/'
+ response = client.get(url)
+ self.assertEquals(response.context['request'].user.is_authenticated(), True)
+ self.assertEquals(response.context['request'].user.is_staff, True)
+ self.assertEqual(response.status_code, 200)
+
+ url = '/en/page_b/'
+ self.assertPageNotFound(url, client)
+ url = '/en/page_b/page_b_b/'
+ self.assertPageNotFound(url, client)
+ url = '/en/page_b/page_b_b/page_b_b_a/'
+ self.assertPageFound(url, client)
+ url = '/en/page_b/page_b_b/page_b_b_b/'
+ self.assertPageFound(url, client)
+ url = '/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/'
+ self.assertPageNotFound(url, client)
+ url = '/en/page_d/'
+ self.assertPageNotFound(url, client)
+ url = '/en/page_d/page_d_a/'
+ self.assertPageFound(url, client)
+#
+ def test_node_staff_access_children_group_2_nostaff(self):
+ """
+ simulate behaviour of group 2 member
+ GROUPNAME_2 = 'group_b_b_ACCESS_CHILDREN'
+ to page_b_b and user is no staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_b_b_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_2_nostaff')
+ client = Client()
+ login_ok = client.login(username='user_2_nostaff', password='user_2_nostaff')
+ self.assertTrue(login_ok)
+ # member of group that has access to this page
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageNotFound(url, client)
+
+ def test_node_staff_access_page_and_descendants_group_3(self):
+ """
+ simulate behaviour of group 3 member
+ group_b_ACCESS_PAGE_AND_DESCENDANTS to page_b
+ and user is staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_b',
+ 'page_b_a',
+ 'page_b_b',
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_b_c',
+ 'page_b_d',
+ 'page_b_d_a',
+ 'page_b_d_b',
+ 'page_b_d_c',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_3')
+ client = Client()
+ login_ok = client.login(username='user_3', password='user_3')
+ self.assertEqual(login_ok , True)
+ url = self.get_pages_root()
+ self.assertPageFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_c/"
+ self.assertPageFound(url, client)
+
+ def test_node_staff_access_page_and_descendants_group_3_nostaff(self):
+ """
+ simulate behaviour of group 3 member
+ group_b_ACCESS_PAGE_AND_DESCENDANTS to page_b
+ user is not staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_b',
+ 'page_b_a',
+ 'page_b_b',
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_b_c',
+ 'page_b_d',
+ 'page_b_d_a',
+ 'page_b_d_b',
+ 'page_b_d_c',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_3_nostaff')
+ client = Client()
+ login_ok = client.login(username='user_3_nostaff', password='user_3_nostaff')
+ self.assertTrue(login_ok)
+ # call /
+ url = self.get_pages_root()
+ response = client.get(url)
+ self.assertEqual(response.status_code, 404)
+ url = "/en/page_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_c/"
+ self.assertPageNotFound(url, client)
+
+ def test_node_staff_access_descendants_group_4(self):
+ """
+ simulate behaviour of group 4 member
+ group_b_b_ACCESS_DESCENDANTS to page_b_b
+ user is staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ 'page_c',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_4')
+ client = Client()
+ login_ok = client.login(username='user_4', password='user_4')
+ self.assertTrue(login_ok)
+ # call /
+ url = self.get_pages_root()
+ self.assertPageFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageNotFound(url, client)
+ # not a direct child
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_b/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_d/"
+ self.assertPageFound(url, client)
+
+ def test_node_staff_access_descendants_group_4_nostaff(self):
+ """
+ simulate behaviour of group 4 member
+ group_b_b_ACCESS_DESCENDANTS to page_b_b
+ user is no staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = [
+ 'page_b_b_a',
+ 'page_b_b_a_a',
+ 'page_b_b_b',
+ 'page_b_b_c',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_4_nostaff')
+ client = Client()
+ login_ok = client.login(username='user_4_nostaff', password='user_4_nostaff')
+ self.assertTrue(login_ok)
+ url = self.get_pages_root()
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_d/"
+ self.assertPageNotFound(url, client)
+
+ def test_node_staff_access_page_group_5(self):
+ """
+ simulate behaviour of group b member
+ group_d_ACCESS_PAGE to page_d
+ user is staff
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_a',
+ 'page_c',
+ 'page_d',
+ 'page_d_a',
+ 'page_d_b',
+ 'page_d_c',
+ 'page_d_d',
+ ]
+ self.assertGrantedVisibility(all_pages, granted, username='user_5')
+ client = Client()
+ login_ok = client.login(username='user_5', password='user_5')
+ self.assertTrue(login_ok)
+ url = self.get_pages_root()
+ self.assertPageFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/page_b_b_a_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageFound(url, client)
+
+ def test_node_staff_access_page_group_5_nostaff(self):
+ """
+ simulate behaviour of group b member
+ group_d_ACCESS_PAGE to page_d
+ nostaff user
+ """
+ self._setup_user_groups()
+ all_pages = self._setup_tree_pages()
+ self._setup_view_restrictions()
+ granted = ['page_d',]
+ self.assertGrantedVisibility(all_pages, granted, username='user_5_nostaff')
+ client = Client()
+ login_ok = client.login(username='user_5_nostaff', password='user_5_nostaff')
+ self.assertTrue(login_ok)
+ url = self.get_pages_root()
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_d/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_b/page_b_b/page_b_b_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/"
+ self.assertPageFound(url, client)
+ url = "/en/page_d/page_d_a/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_b/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_c/"
+ self.assertPageNotFound(url, client)
+ url = "/en/page_d/page_d_d/"
+ self.assertPageNotFound(url, client)
+
View
77 cms/tests/permmod.py
@@ -11,10 +11,11 @@
from cms.test_utils.util.context_managers import SettingsOverride
from cms.utils.page_resolver import get_page_from_path
from cms.utils.permissions import has_generic_permission
+
from django.contrib.auth.models import User, Permission, AnonymousUser, Group
from django.contrib.sites.models import Site
from django.core.management import call_command
-
+from django.db.models import Q
class PermissionModeratorTests(SettingsOverrideTestCase):
"""Permissions and moderator together
@@ -490,20 +491,51 @@ def test_remove_plugin_page_under_moderation(self):
self.assertEquals(CMSPlugin.objects.all().count(), 0)
def test_superuser_can_view(self):
+ url = self.page_b.get_absolute_url(language='en')
with self.login_user_context(self.user_super):
- response = self.client.get("/en/pageb/")
+ response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_staff_can_view(self):
- with self.login_user_context(self.user_staff):
- response = self.client.get("/en/pageb/")
- self.assertEqual(response.status_code, 200)
-
+ url = self.page_b.get_absolute_url(language='en')
+ all_view_perms = PagePermission.objects.filter(can_view=True)
+ # verifiy that the user_staff has access to this page
+ has_perm = False
+ for perm in all_view_perms:
+ if perm.page == self.page_b:
+ if perm.user == self.user_staff:
+ has_perm = True
+ self.assertEqual(has_perm, False)
+ login_ok = self.client.login(username=self.user_staff.username, password=self.user_staff.username)
+ self.assertTrue(login_ok)
+ # really logged in
+ self.assertTrue('_auth_user_id' in self.client.session)
+ login_user_id = self.client.session.get('_auth_user_id')
+ user = User.objects.get(username=self.user_staff.username)
+ self.assertEquals(login_user_id,user.id)
+ response = self.client.get(url)
+ self.assertEqual(response.status_code, 404)
+
def test_user_normal_can_view(self):
url = self.page_b.get_absolute_url(language='en')
+ all_view_perms = PagePermission.objects.filter(can_view=True)
+ # verifiy that the normal_user has access to this page
+ has_perm = False
+ for perm in all_view_perms:
+ if perm.page == self.page_b:
+ if perm.user == self.user_normal:
+ has_perm = True
+ self.assertEqual(has_perm, True)
with self.login_user_context(self.user_normal):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
+
+ # verifiy that the user_non_global has not access to this page
+ has_perm = False
+ for perm in all_view_perms:
+ if perm.page == self.page_b:
+ if perm.user == self.user_non_global:
+ has_perm = True
with self.login_user_context(self.user_non_global):
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
@@ -513,26 +545,47 @@ def test_user_normal_can_view(self):
def test_user_globalpermission(self):
# Global user
+ user_global = User(username="global", is_active=True)
+ user_global.set_password("global")
+ user_global.save()
with self.login_user_context(self.user_super):
- user_global = User(username="global", is_active=True)
- user_global.set_password("global")
- user_global.save()
user_global = create_page_user(user_global, user_global)
user_global.is_staff = False
user_global.save() # Prevent is_staff permission
global_page = create_page("global", "nav_playground.html", "en",
published=True)
global_page = publish_page(global_page, user_global, approve=True)
# it's allowed for the normal user to view the page
- assign_user_to_page(global_page, user_global,
- global_permission=True, can_view=True)
+ assign_user_to_page(global_page, user_global,
+ global_permission=True, can_view=True)
url = global_page.get_absolute_url('en')
-
+ all_view_perms = PagePermission.objects.filter(can_view=True)
+ has_perm = False
+ for perm in all_view_perms:
+ if perm.page == self.page_b and perm.user == user_global:
+ has_perm = True
+ self.assertEqual(has_perm, False)
+
+ global_page_perm_q = Q(user=user_global) & Q(can_view=True)
+ global_view_perms = GlobalPagePermission.objects.filter(global_page_perm_q).exists()
+ self.assertEqual(global_view_perms, True)
+
+ # user_global
with self.login_user_context(user_global):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
+ # self.non_user_global
+ has_perm = False
+ for perm in all_view_perms:
+ if perm.page == self.page_b and perm.user == self.user_non_global:
+ has_perm = True
+ self.assertEqual(has_perm, False)
+ global_page_perm_q = Q(user=self.user_non_global) & Q(can_view=True)
+ global_view_perms = GlobalPagePermission.objects.filter(global_page_perm_q).exists()
+ self.assertEqual(global_view_perms, False)
+
with self.login_user_context(self.user_non_global):
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
View
10 cms/utils/permissions.py
@@ -98,11 +98,11 @@ def has_page_change_permission(request):
return False
def get_any_page_view_permissions(request, page):
- from cms.utils.plugins import current_site
- return PagePermission.objects.filter(
- page__pk=page.pk,
- page__site=current_site(request),
- can_view=True)
+ """
+ Used by the admin template tag is_restricted
+ """
+ return PagePermission.objects.for_page(page=page).filter(can_view=True)
+
def get_user_permission_level(user):
Something went wrong with that request. Please try again.