forked from ungleich-public/dynamicweb
764 lines
32 KiB
Python
764 lines
32 KiB
Python
from unittest.mock import patch
|
|
|
|
from django.contrib.admin.sites import site
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AnonymousUser, Group, Permission
|
|
from django.contrib.sites.models import Site
|
|
from django.db.models import Q
|
|
from django.test.client import RequestFactory
|
|
from django.test.utils import override_settings
|
|
|
|
from cms.admin.forms import save_permissions
|
|
from cms.api import assign_user_to_page, create_page, create_page_user
|
|
from cms.cms_menus import get_visible_page_contents
|
|
from cms.models import ACCESS_PAGE, CMSPlugin, Page, PageContent
|
|
from cms.models.permissionmodels import (
|
|
ACCESS_PAGE_AND_DESCENDANTS,
|
|
GlobalPagePermission,
|
|
PagePermission,
|
|
)
|
|
from cms.test_utils.testcases import CMSTestCase
|
|
from cms.test_utils.util.context_managers import override_placeholder_conf
|
|
from cms.test_utils.util.fuzzy_int import FuzzyInt
|
|
from cms.utils.page_permissions import user_can_view_page
|
|
from cms.utils.urlutils import admin_reverse
|
|
|
|
|
|
@override_settings(CMS_PERMISSION=True)
|
|
class PermissionModeratorTests(CMSTestCase):
|
|
"""Permissions and moderator together
|
|
|
|
Fixtures contains 3 users and 1 published page and some other stuff
|
|
|
|
Users:
|
|
1. `super`: superuser
|
|
2. `master`: user with permissions to all applications
|
|
3. `slave`: user assigned to page `slave-home`
|
|
|
|
Pages:
|
|
1. `home`:
|
|
- published page
|
|
- master can do anything on its subpages, but not on home!
|
|
|
|
2. `master`:
|
|
- published page
|
|
- created by super
|
|
- `master` can do anything on it and its descendants
|
|
- subpages:
|
|
|
|
3. `slave-home`:
|
|
- not published
|
|
- assigned slave user which can add/change/delete/
|
|
move/publish this page and its descendants
|
|
- `master` user want to moderate this page and all descendants
|
|
|
|
4. `pageA`:
|
|
- created by super
|
|
- master can add/change/delete on it and descendants
|
|
"""
|
|
# TODO: Split this test case into one that tests publish functionality, and
|
|
# TODO: one that tests permission inheritance. This is too complex.
|
|
|
|
def setUp(self):
|
|
# create super user
|
|
self.user_super = self._create_user("super", is_staff=True, is_superuser=True)
|
|
|
|
self.user_staff = self._create_user("staff", is_staff=True, add_default_permissions=True)
|
|
self.add_permission(self.user_staff, 'publish_page')
|
|
|
|
self.user_master = self._create_user("master", is_staff=True, add_default_permissions=True)
|
|
self.add_permission(self.user_master, 'publish_page')
|
|
|
|
self.user_slave = self._create_user("slave", is_staff=True, add_default_permissions=True)
|
|
|
|
self.user_normal = self._create_user("normal", is_staff=False)
|
|
self.user_normal.user_permissions.add(Permission.objects.get(codename='publish_page'))
|
|
|
|
with self.login_user_context(self.user_super):
|
|
self.home_page = create_page("home", "nav_playground.html", "en",
|
|
created_by=self.user_super)
|
|
|
|
# master page & master user
|
|
self.master_page = create_page("master", "nav_playground.html", "en")
|
|
|
|
# create non global, non staff user
|
|
self.user_non_global = self._create_user("nonglobal")
|
|
|
|
# assign master user under home page
|
|
assign_user_to_page(self.home_page, self.user_master,
|
|
grant_on=ACCESS_PAGE_AND_DESCENDANTS, grant_all=True)
|
|
|
|
# and to master page
|
|
assign_user_to_page(self.master_page, self.user_master,
|
|
grant_on=ACCESS_PAGE_AND_DESCENDANTS, grant_all=True)
|
|
|
|
# slave page & slave user
|
|
|
|
self.slave_page = create_page("slave-home", "col_two.html", "en",
|
|
parent=self.master_page, created_by=self.user_super)
|
|
|
|
assign_user_to_page(self.slave_page, self.user_slave, grant_all=True)
|
|
|
|
# create page_b
|
|
self.page_b = create_page("pageB", "nav_playground.html", "en", created_by=self.user_super)
|
|
# Normal user
|
|
|
|
# it's allowed for the normal user to view the page
|
|
assign_user_to_page(self.page_b, self.user_normal, can_view=True)
|
|
|
|
# create page_a - sample page from master
|
|
|
|
page_a = create_page("pageA", "nav_playground.html", "en",
|
|
created_by=self.user_super)
|
|
assign_user_to_page(page_a, self.user_master,
|
|
can_add=True, can_change=True, can_delete=True, can_publish=True,
|
|
can_move_page=True)
|
|
|
|
def _add_plugin(self, user, page):
|
|
"""
|
|
Add a plugin using the test client to check for permissions.
|
|
"""
|
|
with self.login_user_context(user):
|
|
placeholder = page.get_placeholders('en')[0]
|
|
data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}
|
|
endpoint = self.get_add_plugin_uri(
|
|
placeholder=placeholder,
|
|
plugin_type='LinkPlugin',
|
|
language='en',
|
|
)
|
|
response = self.client.post(endpoint, data)
|
|
self.assertEqual(response.status_code, 200)
|
|
return response.content.decode('utf8')
|
|
|
|
def test_super_can_add_page_to_root(self):
|
|
with self.login_user_context(self.user_super):
|
|
response = self.client.get(self.get_page_add_uri('en'))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_master_cannot_add_page_to_root(self):
|
|
with self.login_user_context(self.user_master):
|
|
response = self.client.get(self.get_page_add_uri('en'))
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
def test_slave_cannot_add_page_to_root(self):
|
|
with self.login_user_context(self.user_slave):
|
|
response = self.client.get(self.get_page_add_uri('en'))
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
@override_placeholder_conf(
|
|
{
|
|
'col_left': {
|
|
'default_plugins': [
|
|
{
|
|
'plugin_type': 'TextPlugin',
|
|
'values': {
|
|
'body': 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Culpa, repellendus, '
|
|
'delectus, quo quasi ullam inventore quod quam aut voluptatum aliquam voluptatibus '
|
|
'harum officiis officia nihil minus unde accusamus dolorem repudiandae.'
|
|
},
|
|
},
|
|
]
|
|
},
|
|
},
|
|
)
|
|
def test_default_plugins(self):
|
|
with self.login_user_context(self.user_slave):
|
|
self.assertEqual(CMSPlugin.objects.count(), 0)
|
|
response = self.client.get(self.slave_page.get_absolute_url(), {'edit': 1})
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(CMSPlugin.objects.count(), 1)
|
|
|
|
def test_super_can_add_plugin(self):
|
|
self._add_plugin(self.user_super, page=self.slave_page)
|
|
|
|
def test_master_can_add_plugin(self):
|
|
self._add_plugin(self.user_master, page=self.slave_page)
|
|
|
|
def test_slave_can_add_plugin(self):
|
|
self._add_plugin(self.user_slave, page=self.slave_page)
|
|
|
|
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(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_staff_can_view(self):
|
|
url = self.page_b.get_absolute_url(language='en')
|
|
all_view_perms = PagePermission.objects.filter(can_view=True)
|
|
# verify 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=getattr(self.user_staff, get_user_model().USERNAME_FIELD),
|
|
password=getattr(self.user_staff, get_user_model().USERNAME_FIELD))
|
|
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 = get_user_model().objects.get(pk=self.user_staff.pk)
|
|
self.assertEqual(str(login_user_id), str(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)
|
|
# verify that the normal_user has access to this page
|
|
normal_has_perm = False
|
|
for perm in all_view_perms:
|
|
if perm.page == self.page_b:
|
|
if perm.user == self.user_normal:
|
|
normal_has_perm = True
|
|
self.assertTrue(normal_has_perm)
|
|
with self.login_user_context(self.user_normal):
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# verify that the user_non_global has not access to this page
|
|
non_global_has_perm = False
|
|
for perm in all_view_perms:
|
|
if perm.page == self.page_b:
|
|
if perm.user == self.user_non_global:
|
|
non_global_has_perm = True
|
|
self.assertFalse(non_global_has_perm)
|
|
with self.login_user_context(self.user_non_global):
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
# non logged in user
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
def test_user_globalpermission(self):
|
|
# Global user
|
|
user_global = self._create_user("global")
|
|
|
|
with self.login_user_context(self.user_super):
|
|
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")
|
|
# Removed call since global page user doesn't have publish permission
|
|
# global_page = publish_page(global_page, user_global)
|
|
# 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)
|
|
|
|
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)
|
|
|
|
def test_anonymous_user_public_for_all(self):
|
|
url = self.page_b.get_absolute_url('en')
|
|
with self.settings(CMS_PUBLIC_FOR='all'):
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
def test_anonymous_user_public_for_none(self):
|
|
# default of when to show pages to anonymous user doesn't take
|
|
# global permissions into account
|
|
url = self.page_b.get_absolute_url('en')
|
|
with self.settings(CMS_PUBLIC_FOR=None):
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
def test_page_content_reflects_page_publish_permission(self):
|
|
"""
|
|
Test that the page content object gets its publish permission from the
|
|
page object.
|
|
"""
|
|
page = create_page('test', 'nav_playground.html', 'en')
|
|
page_content = page.get_content_obj("en")
|
|
|
|
user = self.get_standard_user()
|
|
assign_user_to_page(page, user, can_publish=True)
|
|
with patch.object(page, "has_publish_permission") as page_has_publish_permission:
|
|
self.assertTrue(page_content.has_publish_permission(user))
|
|
page_has_publish_permission.assert_called_once_with(user)
|
|
|
|
|
|
class ViewPermissionBaseTests(CMSTestCase):
|
|
|
|
def setUp(self):
|
|
self.page = create_page('testpage', 'nav_playground.html', 'en')
|
|
self.page_content = self.page.get_content_obj("en")
|
|
self.site = Site.objects.get_current()
|
|
|
|
def get_request(self, user=None):
|
|
attrs = {
|
|
'user': user or AnonymousUser(),
|
|
'REQUEST': {},
|
|
'POST': {},
|
|
'GET': {},
|
|
'session': {},
|
|
}
|
|
return type('Request', (object,), attrs)
|
|
|
|
def assertViewAllowed(self, page, user=None):
|
|
if not user:
|
|
user = AnonymousUser()
|
|
self.assertTrue(user_can_view_page(user, page))
|
|
|
|
def assertViewNotAllowed(self, page, user=None):
|
|
if not user:
|
|
user = AnonymousUser()
|
|
self.assertFalse(user_can_view_page(user, page))
|
|
|
|
|
|
@override_settings(
|
|
CMS_PERMISSION=False,
|
|
CMS_PUBLIC_FOR='staff',
|
|
)
|
|
class BasicViewPermissionTests(ViewPermissionBaseTests):
|
|
"""
|
|
Test functionality with CMS_PERMISSION set to false, as this is the
|
|
normal use case
|
|
"""
|
|
|
|
@override_settings(CMS_PUBLIC_FOR="all")
|
|
def test_unauth_public(self):
|
|
request = self.get_request()
|
|
with self.assertNumQueries(0):
|
|
self.assertViewAllowed(self.page)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [self.page_content])
|
|
|
|
def test_unauth_non_access(self):
|
|
request = self.get_request()
|
|
with self.assertNumQueries(0):
|
|
self.assertViewNotAllowed(self.page)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [])
|
|
|
|
@override_settings(CMS_PUBLIC_FOR="all")
|
|
def test_staff_public_all(self):
|
|
user = self.get_staff_user_with_no_permissions()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(0):
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site),
|
|
[self.page_content])
|
|
|
|
def test_staff_public_staff(self):
|
|
user = self.get_staff_user_with_no_permissions()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(0):
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site),
|
|
[self.page_content])
|
|
|
|
def test_staff_basic_auth(self):
|
|
user = self.get_staff_user_with_no_permissions()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(0):
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site),
|
|
[self.page_content])
|
|
|
|
@override_settings(CMS_PUBLIC_FOR="all")
|
|
def test_normal_basic_auth(self):
|
|
user = self.get_standard_user()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(0):
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [self.page_content])
|
|
|
|
|
|
@override_settings(
|
|
CMS_PERMISSION=True,
|
|
CMS_PUBLIC_FOR='none'
|
|
)
|
|
class UnrestrictedViewPermissionTests(ViewPermissionBaseTests):
|
|
"""
|
|
Test functionality with CMS_PERMISSION set to True but no restrictions
|
|
apply to this specific page
|
|
"""
|
|
|
|
def test_unauth_non_access(self):
|
|
request = self.get_request()
|
|
|
|
with self.assertNumQueries(1):
|
|
"""
|
|
The query is:
|
|
PagePermission query for the affected page (is the page restricted?)
|
|
"""
|
|
self.assertViewNotAllowed(self.page)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [])
|
|
|
|
def test_global_access(self):
|
|
user = self.get_standard_user()
|
|
GlobalPagePermission.objects.create(can_view=True, user=user)
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(4):
|
|
"""The queries are:
|
|
PagePermission query for the affected page (is the page restricted?)
|
|
Generic django permission lookup
|
|
content type lookup by permission lookup
|
|
GlobalPagePermission query for the page site
|
|
"""
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [self.page_content])
|
|
|
|
def test_normal_denied(self):
|
|
user = self.get_standard_user()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(4):
|
|
"""
|
|
The queries are:
|
|
PagePermission query for the affected page (is the page restricted?)
|
|
GlobalPagePermission query for the page site
|
|
User permissions query
|
|
Content type query
|
|
"""
|
|
self.assertViewNotAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, [self.page_content], self.site), [])
|
|
|
|
|
|
@override_settings(
|
|
CMS_PERMISSION=True,
|
|
CMS_PUBLIC_FOR='all'
|
|
)
|
|
class RestrictedViewPermissionTests(ViewPermissionBaseTests):
|
|
"""
|
|
Test functionality with CMS_PERMISSION set to True and view restrictions
|
|
apply to this specific page
|
|
"""
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.group = Group.objects.create(name='testgroup')
|
|
self.pages = [self.page]
|
|
self.page_contents = [self.page.get_content_obj("en")]
|
|
self.expected = [self.page.get_content_obj("en")]
|
|
PagePermission.objects.create(page=self.page, group=self.group, can_view=True, grant_on=ACCESS_PAGE)
|
|
|
|
def test_unauthed(self):
|
|
request = self.get_request()
|
|
with self.assertNumQueries(1):
|
|
"""The queries are:
|
|
PagePermission query for the affected page (is the page restricted?)
|
|
"""
|
|
self.assertViewNotAllowed(self.page)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), [])
|
|
|
|
def test_page_permissions(self):
|
|
user = self.get_standard_user()
|
|
request = self.get_request(user)
|
|
PagePermission.objects.create(can_view=True, user=user, page=self.page, grant_on=ACCESS_PAGE)
|
|
|
|
with self.assertNumQueries(5):
|
|
"""
|
|
The queries are:
|
|
PagePermission query (is this page restricted)
|
|
content type lookup (x2)
|
|
GlobalpagePermission query for user
|
|
PagePermission query for this user
|
|
"""
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), self.expected)
|
|
|
|
def test_page_group_permissions(self):
|
|
user = self.get_standard_user()
|
|
user.groups.add(self.group)
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(5):
|
|
"""
|
|
The queries are:
|
|
PagePermission query (is this page restricted)
|
|
content type lookup (x2)
|
|
GlobalpagePermission query for user
|
|
PagePermission query for user
|
|
"""
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), self.expected)
|
|
|
|
def test_global_permission(self):
|
|
user = self.get_standard_user()
|
|
GlobalPagePermission.objects.create(can_view=True, user=user)
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(4):
|
|
"""
|
|
The queries are:
|
|
PagePermission query (is this page restricted)
|
|
Generic django permission lookup
|
|
content type lookup by permission lookup
|
|
GlobalpagePermission query for user
|
|
"""
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), self.expected)
|
|
|
|
def test_basic_perm_denied(self):
|
|
user = self.get_staff_user_with_no_permissions()
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(5):
|
|
"""
|
|
The queries are:
|
|
PagePermission query (is this page restricted)
|
|
content type lookup x2
|
|
GlobalpagePermission query for user
|
|
PagePermission query for this user
|
|
"""
|
|
self.assertViewNotAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), [])
|
|
|
|
def test_basic_perm(self):
|
|
user = self.get_standard_user()
|
|
user.user_permissions.add(Permission.objects.get(codename='view_page'))
|
|
request = self.get_request(user)
|
|
|
|
with self.assertNumQueries(3):
|
|
"""
|
|
The queries are:
|
|
PagePermission query (is this page restricted)
|
|
Generic django permission lookup
|
|
content type lookup by permission lookup
|
|
"""
|
|
self.assertViewAllowed(self.page, user)
|
|
|
|
self.assertEqual(get_visible_page_contents(request, self.page_contents, self.site), self.expected)
|
|
|
|
|
|
class GlobalPermissionTests(CMSTestCase):
|
|
|
|
def test_emulate_admin_index(self):
|
|
""" Call methods that emulate the adminsite instance's index.
|
|
This test was basically the reason for the new manager, in light of the
|
|
problem highlighted in ticket #1120, which asserts that giving a user
|
|
no site-specific rights when creating a GlobalPagePermission should
|
|
allow access to all sites.
|
|
"""
|
|
# create and then ignore this user.
|
|
superuser = self._create_user("super", is_staff=True, is_active=True,
|
|
is_superuser=True)
|
|
superuser.set_password("super")
|
|
superuser.save()
|
|
|
|
site_1 = Site.objects.get(pk=1)
|
|
site_2 = Site.objects.create(domain='example2.com', name='example2.com')
|
|
|
|
SITES = [site_1, site_2]
|
|
|
|
# create 2 staff users
|
|
USERS = [
|
|
self._create_user("staff", is_staff=True, is_active=True),
|
|
self._create_user("staff_2", is_staff=True, is_active=True),
|
|
]
|
|
for user in USERS:
|
|
user.set_password('staff')
|
|
# reuse the same methods the UserPage form does.
|
|
# Note that it internally calls .save(), as we've not done so.
|
|
save_permissions({
|
|
'can_add_page': True,
|
|
'can_change_page': True,
|
|
'can_delete_page': False
|
|
}, user)
|
|
|
|
GlobalPagePermission.objects.create(can_add=True, can_change=True,
|
|
can_delete=False, user=USERS[0])
|
|
# we're querying here to ensure that even though we've created two users
|
|
# above, we should have successfully filtered to just one perm.
|
|
self.assertEqual(1, GlobalPagePermission.objects.with_user(USERS[0]).count())
|
|
|
|
# this will confirm explicit permissions still work, by adding the first
|
|
# site instance to the many2many relationship 'sites'
|
|
GlobalPagePermission.objects.create(can_add=True, can_change=True,
|
|
can_delete=False,
|
|
user=USERS[1]).sites.add(SITES[0])
|
|
self.assertEqual(1, GlobalPagePermission.objects.with_user(USERS[1]).count())
|
|
|
|
create_page(title="master", template="nav_playground.html",
|
|
language="en", in_navigation=True, slug='/')
|
|
|
|
with self.settings(CMS_PERMISSION=True):
|
|
# for all users, they should have access to site 1
|
|
request = RequestFactory().get(path='/')
|
|
# Fake session
|
|
request.session = {}
|
|
request.current_page = None
|
|
for user in USERS:
|
|
request.user = user
|
|
# Note, the query count is inflated by doing additional lookups
|
|
# because there's a site param in the request.
|
|
# max_queries = 5 for >dj21 because it's introduce default view permissions
|
|
max_queries = 5
|
|
with self.assertNumQueries(FuzzyInt(3, max_queries)):
|
|
# internally this calls PageAdmin.has_[add|change|delete|view]_permission()
|
|
expected_perms = {'add': True, 'change': True, 'delete': False}
|
|
expected_perms.update({'view': expected_perms['change']})
|
|
self.assertEqual(expected_perms, site._registry[PageContent].get_model_perms(request))
|
|
|
|
# can't use the above loop for this test, as we're testing that
|
|
# user 1 has access, but user 2 does not, as they are only assigned
|
|
# to site 1
|
|
request = RequestFactory().get(path=f'/?site={site_2.pk}')
|
|
request.current_page = None
|
|
request.session = {}
|
|
|
|
# Refresh internal user cache
|
|
USERS[0] = self.reload(USERS[0])
|
|
USERS[1] = self.reload(USERS[1])
|
|
|
|
# As before, the query count is inflated by doing additional lookups
|
|
# because there's a site param in the request
|
|
with self.assertNumQueries(FuzzyInt(5, 15)):
|
|
# this user shouldn't have access to site 2
|
|
request.user = USERS[1]
|
|
expected_perms = {'add': False, 'change': False, 'delete': False}
|
|
expected_perms.update({'view': False})
|
|
self.assertEqual(expected_perms, site._registry[PageContent].get_model_perms(request))
|
|
# but, going back to the first user, they should.
|
|
request = RequestFactory().get('/', data={'site__exact': site_2.pk})
|
|
request.user = USERS[0]
|
|
request.current_page = None
|
|
request.session = {}
|
|
expected_perms = {'add': True, 'change': True, 'delete': False}
|
|
expected_perms.update({'view': expected_perms['change']})
|
|
self.assertEqual(expected_perms, site._registry[PageContent].get_model_perms(request))
|
|
|
|
def test_has_page_add_permission_with_target(self):
|
|
page = create_page('Test', 'nav_playground.html', 'en')
|
|
user = self._create_user('user')
|
|
request = RequestFactory().get('/', data={'target': page.pk})
|
|
request.session = {}
|
|
request.user = user
|
|
has_perm = site._registry[Page].has_add_permission(request)
|
|
self.assertFalse(has_perm)
|
|
|
|
|
|
@override_settings(CMS_PERMISSION=True)
|
|
class AddPageParentPermissionTests(CMSTestCase):
|
|
"""The parent a page is created under is submitted in the POST body, while
|
|
``PageAdmin.has_add_permission`` only sees the one in the query string. Both
|
|
have to be checked, otherwise an editor confined to one subtree can point the
|
|
permission check at a page they may edit and create the page elsewhere."""
|
|
|
|
def setUp(self):
|
|
self.home = create_page('home', 'nav_playground.html', 'en')
|
|
self.allowed = create_page('allowed', 'nav_playground.html', 'en', parent=self.home)
|
|
self.forbidden = create_page('forbidden', 'nav_playground.html', 'en', parent=self.home)
|
|
|
|
self.editor = self._create_user('editor', is_staff=True)
|
|
self.editor.user_permissions.add(*Permission.objects.filter(
|
|
codename__in=[
|
|
'add_page', 'change_page', 'view_page',
|
|
'add_pagecontent', 'change_pagecontent', 'view_pagecontent',
|
|
]
|
|
))
|
|
PagePermission.objects.create(
|
|
page=self.allowed,
|
|
user=self.editor,
|
|
can_add=True,
|
|
can_change=True,
|
|
grant_on=ACCESS_PAGE_AND_DESCENDANTS,
|
|
)
|
|
|
|
def _add_page(self, slug, query_parent=None, body_parent=None):
|
|
url = admin_reverse('cms_pagecontent_add') + '?language=en'
|
|
if query_parent:
|
|
url += f'&parent_page={query_parent.pk}'
|
|
return self.client.post(url, {
|
|
'title': slug,
|
|
'slug': slug,
|
|
'parent_page': str(body_parent.pk) if body_parent else '',
|
|
})
|
|
|
|
def test_add_below_allowed_parent(self):
|
|
with self.login_user_context(self.editor):
|
|
response = self._add_page('ok', query_parent=self.allowed, body_parent=self.allowed)
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertEqual(Page.objects.filter(parent=self.allowed).count(), 1)
|
|
|
|
def test_add_below_forbidden_parent_is_denied(self):
|
|
with self.login_user_context(self.editor):
|
|
response = self._add_page('nope', query_parent=self.forbidden, body_parent=self.forbidden)
|
|
self.assertEqual(response.status_code, 403)
|
|
self.assertFalse(Page.objects.filter(parent=self.forbidden).exists())
|
|
|
|
def test_forbidden_parent_in_body_is_denied(self):
|
|
"""The query string points at a page the editor may add to, the body at one they may not."""
|
|
with self.login_user_context(self.editor):
|
|
response = self._add_page('nope', query_parent=self.allowed, body_parent=self.forbidden)
|
|
self.assertContains(response, 'You do not have permission to add a page here.')
|
|
self.assertFalse(Page.objects.filter(parent=self.forbidden).exists())
|
|
|
|
def test_empty_parent_in_body_is_denied(self):
|
|
"""An empty parent in the body would create a root page."""
|
|
root_pages = Page.objects.filter(parent=None).count()
|
|
with self.login_user_context(self.editor):
|
|
response = self._add_page('nope', query_parent=self.allowed, body_parent=None)
|
|
self.assertContains(response, 'You do not have permission to add a page here.')
|
|
self.assertEqual(Page.objects.filter(parent=None).count(), root_pages)
|
|
|
|
def test_add_translation_ignores_the_parent(self):
|
|
"""Adding a translation submits no parent, the permission is checked
|
|
against ``cms_page`` instead. The empty parent must not deny it."""
|
|
editor = self._create_user('global_editor', is_staff=True)
|
|
editor.user_permissions.add(*Permission.objects.filter(
|
|
codename__in=[
|
|
'add_page', 'change_page', 'view_page',
|
|
'add_pagecontent', 'change_pagecontent', 'view_pagecontent',
|
|
]
|
|
))
|
|
GlobalPagePermission.objects.create(user=editor, can_add=True, can_change=True)
|
|
|
|
url = admin_reverse('cms_pagecontent_add') + f'?language=de&cms_page={self.allowed.pk}'
|
|
with self.login_user_context(editor):
|
|
response = self.client.post(url, {
|
|
'title': 'erlaubt',
|
|
'slug': 'erlaubt',
|
|
'cms_page': str(self.allowed.pk),
|
|
'parent_page': '',
|
|
})
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertTrue(self.allowed.has_translation('de'))
|