Skip to content

Commit

Permalink
Merge pull request #5428 from czpython/fixes/3.3.x/5422
Browse files Browse the repository at this point in the history
Fixed #5422 -- Check plugin permissions when deleting page or translation
  • Loading branch information
czpython committed Jun 17, 2016
2 parents 5e67147 + 1186fb3 commit 1a83e97
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 6 deletions.
40 changes: 37 additions & 3 deletions cms/admin/pageadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,37 @@ def has_delete_permission(self, request, obj=None):
"""
if get_cms_setting('PERMISSION') and obj is not None:
return obj.has_delete_permission(request)
return super(PageAdmin, self).has_delete_permission(request, obj)

can_delete = super(PageAdmin, self).has_delete_permission(request, obj)

if not can_delete or not obj:
return False

user = request.user
languages = obj.get_languages()
placeholders = obj.placeholders.filter(cmsplugin__language__in=languages)

for placeholder in placeholders.iterator():
if not placeholder.has_clear_permission(user, languages):
return False
return True

def has_delete_translation_permission(self, request, language, obj=None):
if get_cms_setting('PERMISSION') and obj is not None:
return obj.has_delete_permission(request)

can_delete = permissions.has_auth_page_permission(request.user, action='delete')

if not can_delete or not obj:
return False

user = request.user
placeholders = obj.placeholders.filter(cmsplugin__language=language)

for placeholder in placeholders.iterator():
if not placeholder.has_clear_permission(user, [language]):
return False
return True

def has_recover_permission(self, request):
"""
Expand Down Expand Up @@ -644,8 +674,12 @@ def has_clear_placeholder_permission(self, request, placeholder):
return False
if not page.has_change_permission(request):
return False

language = request.GET.get('language', None)
return placeholder.has_clear_permission(request.user, language)

if language is None:
language = get_language_from_request(request)
return placeholder.has_clear_permission(request.user, [language])

@create_revision()
def post_add_plugin(self, request, plugin):
Expand Down Expand Up @@ -1378,7 +1412,7 @@ def delete_translation(self, request, object_id, extra_context=None):
# to determine whether a given object exists.
obj = None

if not self.has_delete_permission(request, obj):
if not self.has_delete_translation_permission(request, language, obj):
return HttpResponseForbidden(force_text(_("You do not have permission to change this page")))

if obj is None:
Expand Down
2 changes: 1 addition & 1 deletion cms/admin/placeholderadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def has_clear_placeholder_permission(self, request, placeholder):
if not placeholder.has_delete_permission(request):
return False
language = request.GET.get('language', None)
return placeholder.has_clear_permission(request.user, language)
return placeholder.has_clear_permission(request.user, [language])

def post_add_plugin(self, request, plugin):
pass
Expand Down
7 changes: 5 additions & 2 deletions cms/models/placeholdermodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,13 @@ def has_add_permission(self, request):
def has_delete_permission(self, request):
return self._get_permission(request, 'delete')

def has_clear_permission(self, user, language):
def has_clear_permission(self, user, languages):
plugin_types = (
self
.get_plugins(language)
.cmsplugin_set
.filter(language__in=languages)
# exclude the clipboard plugin
.exclude(plugin_type='PlaceholderPlugin')
.values_list('plugin_type', flat=True)
.distinct()
)
Expand Down
139 changes: 139 additions & 0 deletions cms/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,73 @@ def test_delete(self):
response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data)
self.assertRedirects(response, URL_CMS_PAGE)

def test_delete_permissions(self):
admin_user, staff_user = self._get_guys()
create_page("home", "nav_playground.html", "en",
created_by=admin_user, published=True)
page = create_page("delete-page", "nav_playground.html", "en",
created_by=admin_user, published=True)
body = page.placeholders.get(slot='body')
add_plugin(body, 'TextPlugin', 'en', body='text')
page.publish('en')

# CMS_PERMISSION is set to True and staff user
# has global permissions set.
with self.settings(CMS_PERMISSION=True):
with self.login_user_context(staff_user):
data = {'post': 'yes'}
response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data)

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(Page.objects.filter(pk=page.pk).exists())

page = create_page("delete-page", "nav_playground.html", "en",
created_by=admin_user, published=True)

# CMS_PERMISSION is set to False and user does not
# have permission to delete any plugins but the page
# has no plugins.
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
data = {'post': 'yes'}
response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data)

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(Page.objects.filter(pk=page.pk).exists())

page = create_page("delete-page", "nav_playground.html", "en",
created_by=admin_user, published=True)
body = page.placeholders.get(slot='body')
add_plugin(body, 'TextPlugin', 'en', body='text')
page.publish('en')

# CMS_PERMISSION is set to False and user does not
# have permission to delete any plugin
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
data = {'post': 'yes'}
response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data)

# assert deleting page was unsuccessful
self.assertEqual(response.status_code, 403)
self.assertTrue(Page.objects.filter(pk=page.pk).exists())

# Give the staff user permission to delete text plugins
staff_user.user_permissions.add(Permission.objects.get(codename='delete_text'))

# CMS_PERMISSION is set to False and user has
# permission to delete text plugins
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
data = {'post': 'yes'}
response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data)

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(Page.objects.filter(pk=page.pk).exists())

def test_delete_diff_language(self):
admin_user = self.get_superuser()
create_page("home", "nav_playground.html", "en",
Expand Down Expand Up @@ -388,6 +455,78 @@ def test_delete_translation(self):
response = self.client.post(URL_CMS_TRANSLATION_DELETE % page.pk, {'language': 'es-mx'})
self.assertRedirects(response, URL_CMS_PAGE)

def test_delete_translation_permissions(self):
admin_user, staff_user = self._get_guys()
page = create_page("delete-page-translation", "nav_playground.html", "en",
created_by=admin_user, published=True)
body = page.placeholders.get(slot='body')
create_title("de", "delete-page-translation-2", page, slug="delete-page-translation-2")
create_title("fr", "delete-page-translation-fr", page.reload(), slug="delete-page-translation-fr")
add_plugin(body, 'TextPlugin', 'de', body='text')

# add a link plugin but never give the user permission to delete it
# all our tests target the german translation.
# this asserts that a plugin in another language does not interfere
# with deleting.
link = add_plugin(body, 'LinkPlugin', 'en', name='link-1')

# CMS_PERMISSION is set to True and staff user
# has global permissions set.
with self.settings(CMS_PERMISSION=True):
with self.login_user_context(staff_user):
response = self.client.post(URL_CMS_TRANSLATION_DELETE % page.pk, {'language': 'de'})

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(page.title_set.filter(language='de').exists())
# LinkPlugin should continue to be
self.assertTrue(body.cmsplugin_set.filter(pk=link.pk).exists())

# the API needs a fresh page object
page = page.reload()
create_title("de", "delete-page-translation-2", page.reload(), slug="delete-page-translation-2")
add_plugin(body, 'TextPlugin', 'de', body='text')

# CMS_PERMISSION is set to False and user does not
# have permission to delete text plugins
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
response = self.client.post(URL_CMS_TRANSLATION_DELETE % page.pk, {'language': 'de'})

# assert deleting page was successful
self.assertEqual(response.status_code, 403)
self.assertTrue(page.title_set.filter(language='de').exists())
# LinkPlugin should continue to be
self.assertTrue(body.cmsplugin_set.filter(pk=link.pk).exists())

# CMS_PERMISSION is set to False and user does not
# have permission to delete any plugins but the translation
# does not contain plugins
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
response = self.client.post(URL_CMS_TRANSLATION_DELETE % page.pk, {'language': 'fr'})

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(page.title_set.filter(language='fr').exists())
# LinkPlugin should continue to be
self.assertTrue(body.cmsplugin_set.filter(pk=link.pk).exists())

# Give the staff user permission to delete text plugins
staff_user.user_permissions.add(Permission.objects.get(codename='delete_text'))

# CMS_PERMISSION is set to False and user has
# permission to delete text plugins
with self.settings(CMS_PERMISSION=False):
with self.login_user_context(staff_user):
response = self.client.post(URL_CMS_TRANSLATION_DELETE % page.pk, {'language': 'de'})

# assert deleting page was successful
self.assertRedirects(response, URL_CMS_PAGE)
self.assertFalse(page.title_set.filter(language='de').exists())
# LinkPlugin should continue to be
self.assertTrue(body.cmsplugin_set.filter(pk=link.pk).exists())

def test_change_dates(self):
admin_user, staff = self._get_guys()

Expand Down

0 comments on commit 1a83e97

Please sign in to comment.