1# -*- coding: utf-8 -*-
2import datetime
3import json
4import sys
5
6from django.contrib import admin
7from django.contrib.sites.models import Site
8from django.core.cache import cache
9from django.forms.models import model_to_dict
10from django.http import HttpRequest
11from django.test.html import HTMLParseError, Parser
12from django.test.utils import override_settings
13from django.urls import clear_url_caches
14from django.utils import six
15from django.utils.encoding import force_text
16from django.utils.timezone import now as tz_now
17from django.utils.translation import override as force_language
18
19from cms import constants
20from cms.admin.pageadmin import PageAdmin
21from cms.api import create_page, add_plugin, create_title
22from cms.appresolver import clear_app_resolvers
23from cms.cache.permissions import get_permission_cache, set_permission_cache
24from cms.constants import PUBLISHER_STATE_DEFAULT, PUBLISHER_STATE_DIRTY
25from cms.middleware.user import CurrentUserMiddleware
26from cms.models.pagemodel import Page, PageType
27from cms.models.permissionmodels import PagePermission
28from cms.models.pluginmodel import CMSPlugin
29from cms.models.titlemodels import EmptyTitle, Title
30from cms.test_utils.testcases import (
31    CMSTestCase, URL_CMS_PAGE, URL_CMS_PAGE_MOVE,
32    URL_CMS_PAGE_ADVANCED_CHANGE, URL_CMS_PAGE_CHANGE, URL_CMS_PAGE_ADD
33)
34from cms.test_utils.project.sampleapp.models import SampleAppConfig
35from cms.test_utils.util.context_managers import LanguageOverride, UserLoginContext
36from cms.utils.conf import get_cms_setting
37from cms.utils.compat.dj import installed_apps
38from cms.utils.page import get_page_from_request
39from cms.utils.urlutils import admin_reverse
40
41
42class PageTreeLiParser(Parser):
43
44    def handle_starttag(self, tag, attrs):
45        # We have to strip out attributes from the <li>
46        # tags in order to compare the values only
47        # Otherwise we'd have to include all attributes
48        # which in this case is not optimal because there's too many
49        # and would require us to hardcode a bunch of stuff here
50        if tag == 'li':
51            attrs = []
52        Parser.handle_starttag(self, tag, attrs)
53
54
55class PageTreeOptionsParser(Parser):
56
57    def handle_starttag(self, tag, attrs):
58        # This parser only cares about the options on the right side
59        # of the page tree for each page.
60        if tag == 'li' and attrs and attrs[-1][0] == 'data-coloptions':
61            attrs = [attrs[-1]]
62        Parser.handle_starttag(self, tag, attrs)
63
64
65class PageTestBase(CMSTestCase):
66    """
67    The purpose of this class is to provide some basic functionality
68    to test methods of the Page admin.
69    """
70    placeholderconf = {'body': {
71        'limits': {
72            'global': 2,
73            'TextPlugin': 1,
74        }
75    }
76    }
77
78    def _add_plugin_to_page(self, page, plugin_type='LinkPlugin', language='en', publish=True):
79        plugin_data = {
80            'TextPlugin': {'body': '<p>text</p>'},
81            'LinkPlugin': {'name': 'A Link', 'external_link': 'https://www.django-cms.org'},
82        }
83        placeholder = page.placeholders.get(slot='body')
84        plugin = add_plugin(placeholder, plugin_type, language, **plugin_data[plugin_type])
85
86        if publish:
87            page.reload().publish(language)
88        return plugin
89
90    def _translation_exists(self, slug=None, title=None):
91        if not slug:
92            slug = 'permissions-de'
93
94        lookup = Title.objects.filter(slug=slug)
95
96        if title:
97            lookup = lookup.filter(title=title)
98        return lookup.exists()
99
100    def _get_add_plugin_uri(self, page, language='en'):
101        placeholder = page.placeholders.get(slot='body')
102        uri = self.get_add_plugin_uri(
103            placeholder=placeholder,
104            plugin_type='LinkPlugin',
105            language=language,
106        )
107        return uri
108
109    def _get_page_data(self, **kwargs):
110        site = Site.objects.get_current()
111        data = {
112            'title': 'permissions',
113            'slug': 'permissions',
114            'language': 'en',
115            'site': site.pk,
116            'template': 'nav_playground.html',
117        }
118        data.update(**kwargs)
119        return data
120
121    def get_page(self, parent=None, site=None,
122                 language=None, template='nav_playground.html'):
123        page_data = self.get_new_page_data_dbfields()
124        return create_page(**page_data)
125
126    def get_admin(self):
127        """
128        Returns a PageAdmin instance.
129        """
130        return PageAdmin(Page, admin.site)
131
132    def get_post_request(self, data):
133        return self.get_request(post_data=data)
134
135    def create_page(self, title=None, **kwargs):
136        return create_page(title or self._testMethodName,
137                           "nav_playground.html", "en", **kwargs)
138
139
140class PageTest(PageTestBase):
141
142    def tearDown(self):
143        cache.clear()
144
145    def test_add_page(self):
146        """
147        Test that the add admin page could be displayed via the admin
148        """
149        superuser = self.get_superuser()
150
151        with self.login_user_context(superuser):
152            response = self.client.get(URL_CMS_PAGE_ADD)
153            self.assertEqual(response.status_code, 200)
154            self.assertContains(response, '<title>Add a page</title>', html=True)
155
156    def test_create_page_admin(self):
157        """
158        Test that a page can be created via the admin
159        """
160        page_data = self.get_new_page_data()
161
162        superuser = self.get_superuser()
163        with self.login_user_context(superuser):
164            self.assertEqual(Title.objects.all().count(), 0)
165            self.assertEqual(Page.objects.all().count(), 0)
166            # crate home and auto publish
167            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
168            self.assertRedirects(response, URL_CMS_PAGE)
169            page_data = self.get_new_page_data()
170            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
171            self.assertRedirects(response, URL_CMS_PAGE)
172
173            #self.assertEqual(Page.objects.all().count(), 2)
174            #self.assertEqual(Title.objects.all().count(), 2)
175
176            title = Title.objects.drafts().get(slug=page_data['slug'])
177            self.assertRaises(Title.DoesNotExist, Title.objects.public().get, slug=page_data['slug'])
178
179            page = title.page
180            page.save()
181            page.publish('en')
182            self.assertEqual(page.get_title(), page_data['title'])
183            self.assertEqual(page.get_slug(), page_data['slug'])
184            self.assertEqual(page.placeholders.all().count(), 2)
185
186            # were public instances created?
187            self.assertEqual(Title.objects.all().count(), 4)
188            title = Title.objects.drafts().get(slug=page_data['slug'])
189            title = Title.objects.public().get(slug=page_data['slug'])
190
191    def test_create_page_with_unconfigured_language(self):
192        """
193        Test that a page can be created via the admin
194        with the request language pointing to a language
195        not configured for the current site
196        """
197        from django.test import Client
198        from django.contrib.auth import get_user_model
199
200        client = Client()
201        superuser = self.get_superuser()
202        Site.objects.create(id=2, name='example-2.com', domain='example-2.com')
203        client.login(
204            username=getattr(superuser, get_user_model().USERNAME_FIELD),
205            password=getattr(superuser, get_user_model().USERNAME_FIELD),
206        )
207        self.assertEqual(Title.objects.all().count(), 0)
208        self.assertEqual(Page.objects.all().count(), 0)
209        # create home and auto publish
210        with self.settings(SITE_ID=2):
211            # url uses "en" as the request language
212            # but the site is configured to use "de" and "fr"
213            response = client.post(URL_CMS_PAGE_ADD, self.get_new_page_data())
214            self.assertRedirects(response, URL_CMS_PAGE)
215            self.assertEqual(Page.objects.filter(node__site=2).count(), 2)
216            self.assertEqual(Title.objects.filter(language='de').count(), 2)
217
218        # The user is on site #1 but switches sites using the site switcher
219        # on the page changelist.
220        client.post(self.get_admin_url(Page, 'changelist'), {'site': 2})
221
222        # url uses "en" as the request language
223        # but the site is configured to use "de" and "fr"
224        response = client.post(URL_CMS_PAGE_ADD, self.get_new_page_data())
225        self.assertRedirects(response, URL_CMS_PAGE)
226        self.assertEqual(Page.objects.filter(node__site=2).count(), 3)
227        self.assertEqual(Title.objects.filter(language='de').count(), 3)
228
229        Site.objects.clear_cache()
230        client.logout()
231
232    def test_create_tree_admin(self):
233        """
234        Test that a tree can be created via the admin
235        """
236        page_1 = self.get_new_page_data()
237
238        superuser = self.get_superuser()
239        with self.login_user_context(superuser):
240            # create home and auto publish
241            response = self.client.post(URL_CMS_PAGE_ADD, page_1)
242            self.assertRedirects(response, URL_CMS_PAGE)
243
244            title_home = Title.objects.drafts().get(slug=page_1['slug'])
245
246            page_2 = self.get_new_page_data(parent_id=title_home.page.node.pk)
247            page_3 = self.get_new_page_data(parent_id=title_home.page.node.pk)
248            page_4 = self.get_new_page_data(parent_id=title_home.page.node.pk)
249
250            response = self.client.post(URL_CMS_PAGE_ADD, page_2)
251            self.assertRedirects(response, URL_CMS_PAGE)
252            response = self.client.post(URL_CMS_PAGE_ADD, page_3)
253            self.assertRedirects(response, URL_CMS_PAGE)
254
255            title_left = Title.objects.drafts().get(slug=page_2['slug'])
256
257            response = self.client.post(URL_CMS_PAGE_ADD + '?target=%s&amp;position=right' % title_left.page.pk, page_4)
258            self.assertRedirects(response, URL_CMS_PAGE)
259
260    def test_slug_collision(self):
261        """
262        Test a slug collision
263        """
264        page_data = self.get_new_page_data()
265        # create first page
266        superuser = self.get_superuser()
267        with self.login_user_context(superuser):
268            # Home
269            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
270            self.assertRedirects(response, URL_CMS_PAGE)
271            # Second root
272            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
273            self.assertRedirects(response, URL_CMS_PAGE)
274
275            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
276            new_page_id = Page.objects.only('id').latest('id').pk
277            expected_error = (
278                '<ul class="errorlist"><li>Page '
279                '<a href="{}" target="_blank">test page 1</a> '
280                'has the same url \'test-page-1\' as current page.</li></ul>'
281            ).format(self.get_admin_url(Page, 'change', new_page_id))
282
283            self.assertEqual(response.status_code, 200)
284            self.assertTrue(response.request['PATH_INFO'].endswith(URL_CMS_PAGE_ADD))
285            self.assertContains(response, expected_error)
286
287    def test_child_slug_collision(self):
288        """
289        Test a slug collision
290        """
291        root = create_page("home", 'nav_playground.html', "en", published=True)
292        page = create_page("page", 'nav_playground.html', "en")
293        sub_page = create_page("subpage", 'nav_playground.html', "en", parent=page)
294        child_page = create_page("child-page", 'nav_playground.html', "en", parent=root)
295        root.set_as_homepage()
296        superuser = self.get_superuser()
297        with self.login_user_context(superuser):
298            # slug collision between two child pages of the same node
299            page_data = self.get_new_page_data(page.node.pk)
300            page_data['slug'] = 'subpage'
301            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
302            expected_markup = (
303                '<ul class="errorlist">'
304                '<li>Page <a href="{}" target="_blank">subpage</a> '
305                'has the same url \'page/subpage\' as current page.</li></ul>'
306            ).format(self.get_admin_url(Page, 'change', sub_page.pk))
307
308            self.assertEqual(response.status_code, 200)
309            self.assertTrue(response.request['PATH_INFO'].endswith(URL_CMS_PAGE_ADD))
310            self.assertContains(response, expected_markup)
311
312            # slug collision between page with no parent and a child page of home-page
313            page_data = self.get_new_page_data()
314            page_data['slug'] = 'child-page'
315            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
316            expected_markup = (
317                '<ul class="errorlist">'
318                '<li>Page <a href="{}" target="_blank">child-page</a> '
319                'has the same url \'child-page\' as current page.</li></ul>'
320            ).format(self.get_admin_url(Page, 'change', child_page.pk))
321
322            self.assertEqual(response.status_code, 200)
323            self.assertTrue(response.request['PATH_INFO'].endswith(URL_CMS_PAGE_ADD))
324            self.assertContains(response, expected_markup)
325
326            # slug collision between two top-level pages
327            page_data = self.get_new_page_data()
328            page_data['slug'] = 'page'
329            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
330            expected_markup = (
331                '<ul class="errorlist">'
332                '<li>Page <a href="{}" target="_blank">page</a> '
333                'has the same url \'page\' as current page.</li></ul>'
334            ).format(self.get_admin_url(Page, 'change', page.pk))
335
336            self.assertEqual(response.status_code, 200)
337            self.assertTrue(response.request['PATH_INFO'].endswith(URL_CMS_PAGE_ADD))
338            self.assertContains(response, expected_markup)
339
340    def test_edit_page(self):
341        """
342        Test that a page can edited via the admin
343        """
344        superuser = self.get_superuser()
345        with self.login_user_context(superuser):
346            page_data = self.get_new_page_data()
347            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
348            page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
349            response = self.client.get(URL_CMS_PAGE_CHANGE % page.id)
350            self.assertEqual(response.status_code, 200)
351            self.assertContains(response, '<title>Change a page</title>', html=True)
352            page_data['title'] = 'changed title'
353            response = self.client.post(URL_CMS_PAGE_CHANGE % page.id, page_data)
354            self.assertRedirects(response, URL_CMS_PAGE)
355            self.assertEqual(page.get_title(), 'changed title')
356
357    def test_edit_page_sets_publisher_dirty(self):
358        """
359        Test that setting and changing a value for a title/page field
360        will cause the title to be marked as dirty (pending changes).
361        """
362        superuser = self.get_superuser()
363
364        with self.login_user_context(superuser):
365            page_data = self.get_new_page_data()
366            self.client.post(URL_CMS_PAGE_ADD, page_data)
367
368        page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
369
370        basic_fields = {
371            'title': ('new title', 'new title 2'),
372            'slug': ('new-slug', 'new-slug-2'),
373            'page_title': ('new page title', 'new page title 2'),
374            'menu_title': ('new menu title', 'new menu title 2'),
375            'meta_description': ('new menu description', 'new menu description 2'),
376        }
377        advanced_fields = {
378            'overwrite_url': ('title-override', 'title-override-2'),
379            'redirect': ('/title-redirect/', '/title-redirect-2/'),
380        }
381
382        set_message = 'setting field {} is not updating publisher status'
383        change_message = 'changing field {} is not updating publisher status'
384
385        with self.login_user_context(superuser):
386            endpoint = self.get_admin_url(Page, 'change', page.pk)
387
388            for field, values in basic_fields.items():
389                # Set the initial value
390                page_data[field] = values[0]
391                self.client.post(endpoint, page_data)
392                self.assertTrue(page.reload().is_dirty('en'), set_message.format(field))
393
394                # Reset the publisher dirty status
395                page.reload().publish('en')
396
397                # Change the initial value=
398                page_data[field] = values[1]
399                self.client.post(endpoint, page_data)
400                self.assertTrue(page.reload().is_dirty('en'), change_message.format(field))
401
402            endpoint = self.get_admin_url(Page, 'advanced', page.pk)
403            page_data['template'] = page.template
404
405            for field, values in advanced_fields.items():
406                # Set the initial value
407                page_data[field] = values[0]
408                self.client.post(endpoint, page_data)
409                self.assertTrue(page.reload().is_dirty('en'), set_message.format(field))
410
411                # Reset the publisher dirty status
412                page.reload().publish('en')
413
414                # Change the initial value
415                page_data[field] = values[1]
416                self.client.post(endpoint, page_data)
417                self.assertTrue(page.reload().is_dirty('en'), change_message.format(field))
418
419    def test_page_redirect_field_validation(self):
420        superuser = self.get_superuser()
421        data = self.get_new_page_data()
422
423        with self.login_user_context(superuser):
424            self.client.post(URL_CMS_PAGE_ADD, data)
425
426        page = Page.objects.get(title_set__slug=data['slug'], publisher_is_draft=True)
427        data = {'template': page.template}
428        endpoint = URL_CMS_PAGE_ADVANCED_CHANGE % page.pk
429        redirect_to = URL_CMS_PAGE
430
431        with self.login_user_context(superuser):
432            data['redirect'] = '/'
433            response = self.client.post(endpoint, data)
434            self.assertRedirects(response, redirect_to)
435
436        with self.login_user_context(superuser):
437            data['redirect'] = '/hello'
438            response = self.client.post(endpoint, data)
439            self.assertRedirects(response, redirect_to)
440
441        with self.login_user_context(superuser):
442            data['redirect'] = '/hello/'
443            response = self.client.post(endpoint, data)
444            self.assertRedirects(response, redirect_to)
445
446        with self.login_user_context(superuser):
447            data['redirect'] = '../hello'
448            response = self.client.post(endpoint, data)
449            self.assertRedirects(response, redirect_to)
450
451        with self.login_user_context(superuser):
452            data['redirect'] = '../hello/'
453            response = self.client.post(endpoint, data)
454            self.assertRedirects(response, redirect_to)
455
456        with self.login_user_context(superuser):
457            data['redirect'] = 'javascript:alert(1)'
458            # Asserts users can't insert javascript call
459            response = self.client.post(endpoint, data)
460            validation_error = '<ul class="errorlist"><li>Enter a valid URL.</li></ul>'
461            self.assertContains(response, validation_error, html=True)
462
463        with self.login_user_context(superuser):
464            data['redirect'] = '<script>alert("test")</script>'
465            # Asserts users can't insert javascript call
466            response = self.client.post(endpoint, data)
467            validation_error = '<ul class="errorlist"><li>Enter a valid URL.</li></ul>'
468            self.assertContains(response, validation_error, html=True)
469
470    def test_moderator_edit_page_redirect(self):
471        """
472        Test that a page can be edited multiple times with moderator
473        """
474        create_page("home", "nav_playground.html", "en", published=True)
475        superuser = self.get_superuser()
476        with self.login_user_context(superuser):
477            page_data = self.get_new_page_data()
478            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
479            self.assertEqual(response.status_code, 302)
480            page = Page.objects.get(title_set__slug=page_data['slug'])
481            response = self.client.get(URL_CMS_PAGE_CHANGE % page.id)
482            self.assertEqual(response.status_code, 200)
483            page_data['template'] = page.template
484            page_data['overwrite_url'] = '/hello/'
485            page_data['has_url_overwrite'] = True
486            response = self.client.post(URL_CMS_PAGE_ADVANCED_CHANGE % page.id, page_data)
487            self.assertRedirects(response, URL_CMS_PAGE)
488            self.assertEqual(page.get_absolute_url(), '/en/hello/')
489            Title.objects.all()[0]
490            page = page.reload()
491            page.publish('en')
492            page_data['title'] = 'new title'
493            response = self.client.post(URL_CMS_PAGE_CHANGE % page.id, page_data)
494            page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
495            self.assertRedirects(response, URL_CMS_PAGE)
496            self.assertEqual(page.get_title(), 'new title')
497
498    def test_meta_description_fields_from_admin(self):
499        """
500        Test that description and keywords tags can be set via the admin
501        """
502        superuser = self.get_superuser()
503        with self.login_user_context(superuser):
504            page_data = self.get_new_page_data()
505            page_data["meta_description"] = "I am a page"
506            self.client.post(URL_CMS_PAGE_ADD, page_data)
507            page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
508            response = self.client.get(URL_CMS_PAGE_CHANGE % page.id)
509            self.assertEqual(response.status_code, 200)
510            page_data['meta_description'] = 'I am a duck'
511            response = self.client.post(URL_CMS_PAGE_CHANGE % page.id, page_data)
512            self.assertRedirects(response, URL_CMS_PAGE)
513            page = Page.objects.get(title_set__slug=page_data["slug"], publisher_is_draft=True)
514            self.assertEqual(page.get_meta_description(), 'I am a duck')
515
516    def test_meta_description_from_template_tags(self):
517        from django import template
518
519        superuser = self.get_superuser()
520        with self.login_user_context(superuser):
521            page_data = self.get_new_page_data()
522            page_data["title"] = "Hello"
523            page_data["meta_description"] = "I am a page"
524            self.client.post(URL_CMS_PAGE_ADD, page_data)
525            page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
526            self.client.post(URL_CMS_PAGE_CHANGE % page.id, page_data)
527            t = template.Template(
528                "{% load cms_tags %}{% page_attribute title %} {% page_attribute meta_description %}")
529            req = HttpRequest()
530            page.save()
531            page.publish('en')
532            req.current_page = page
533            req.GET = {}
534            self.assertEqual(t.render(template.Context({"request": req})), "Hello I am a page")
535
536    def test_page_obj_change_data_from_template_tags(self):
537        from django import template
538
539        superuser = self.get_superuser()
540        with self.login_user_context(superuser):
541            page_data = self.get_new_page_data()
542            change_user = str(superuser)
543            # some databases don't store microseconds, so move the start flag
544            # back by 1 second
545            before_change = tz_now()+datetime.timedelta(seconds=-1)
546            self.client.post(URL_CMS_PAGE_ADD, page_data)
547            page = Page.objects.get(
548                title_set__slug=page_data['slug'],
549                publisher_is_draft=True
550            )
551            self.client.post(URL_CMS_PAGE_CHANGE % page.id, page_data)
552            t = template.Template(
553                "{% load cms_tags %}{% page_attribute changed_by %} changed "
554                "on {% page_attribute changed_date as page_change %}"
555                "{{ page_change|date:'Y-m-d\TH:i:s' }}"
556            )
557            req = HttpRequest()
558            page.save()
559            page.publish('en')
560            after_change = tz_now()
561            req.current_page = page
562            req.GET = {}
563
564            actual_result = t.render(template.Context({"request": req}))
565            desired_result = "{0} changed on {1}".format(
566                change_user,
567                actual_result[-19:]
568            )
569            save_time = datetime.datetime.strptime(
570                actual_result[-19:],
571                "%Y-%m-%dT%H:%M:%S"
572            )
573
574            self.assertEqual(actual_result, desired_result)
575            # direct time comparisons are flaky, so we just check if the
576            # page's changed_date is within the time range taken by this test
577            self.assertLessEqual(before_change, save_time)
578            self.assertLessEqual(save_time, after_change)
579
580    def test_delete_page_confirmation(self):
581        superuser = self.get_superuser()
582        page_a = create_page("page_a", "nav_playground.html", "en", published=True)
583        create_page("page_a_a", "nav_playground.html", "en", parent=page_a, published=True)
584        page_a_b = create_page("page_a_b", "nav_playground.html", "en", parent=page_a, published=True)
585        create_page("page_a_b_a", "nav_playground.html", "en", parent=page_a_b, published=True)
586        endpoint = self.get_admin_url(Page, 'delete', page_a.pk)
587
588        page_tree = [page_a] + list(page_a.get_descendant_pages())
589        row_markup = '<a href="%s">%s</a>'
590
591        with self.login_user_context(superuser):
592            response = self.client.get(endpoint)
593            for page in page_tree:
594                edit_url = self.get_admin_url(Page, 'change', page.pk)
595                page_markup = row_markup % (edit_url, page.get_title('en'))
596                self.assertContains(response, page_markup, html=True)
597
598    def test_publish_homepage_with_children(self):
599        homepage = create_page("home", "nav_playground.html", "en", published=True)
600        homepage.set_as_homepage()
601        pending_child_1 = create_page(
602            "child-1",
603            "nav_playground.html",
604            language="en",
605            parent=homepage,
606            published=True,
607        )
608        pending_child_2 = create_page(
609            "child-2",
610            "nav_playground.html",
611            language="en",
612            parent=homepage,
613            published=True,
614        )
615        endpoint = self.get_admin_url(Page, 'publish_page', homepage.pk, 'en')
616        expected_tree = [
617            (homepage, ''),
618            (pending_child_1, 'child-1'),
619            (pending_child_2, 'child-2'),
620        ]
621
622        with self.login_user_context(self.get_superuser()):
623            self.client.post(endpoint)
624
625            for page, url_path in expected_tree:
626                self.assertPublished(page)
627                page._clear_internal_cache()
628                self.assertEqual(page.get_path('en'), url_path)
629                self.assertEqual(page.publisher_public.get_path('en'), url_path)
630
631    def test_copy_page(self):
632        """
633        Test that a page can be copied via the admin
634        """
635        page_a = create_page("page_a", "nav_playground.html", "en", published=True)
636        page_a_a = create_page("page_a_a", "nav_playground.html", "en",
637                               parent=page_a, published=True, reverse_id="hello")
638        create_page("page_a_a_a", "nav_playground.html", "en", parent=page_a_a, published=True)
639
640        page_b = create_page("page_b", "nav_playground.html", "en", published=True)
641        page_b_a = create_page("page_b_b", "nav_playground.html", "en",
642                               parent=page_b, published=True)
643
644        count = Page.objects.drafts().count()
645
646        superuser = self.get_superuser()
647        with self.login_user_context(superuser):
648            self.copy_page(page_a, page_b_a)
649
650        self.assertEqual(Page.objects.drafts().count() - count, 3)
651
652    def test_copy_page_under_home(self):
653        """
654        Users should be able to copy a page and paste under the home page.
655        """
656        homepage = create_page("home", "nav_playground.html", "en", published=True)
657        homepage.set_as_homepage()
658
659        root_page_a = create_page("root-a", "nav_playground.html", "en", published=True)
660
661        with self.login_user_context(self.get_superuser()):
662            self.copy_page(root_page_a, homepage)
663
664    def test_copy_page_with_plugins(self):
665        """
666        Copying a page with plugins should copy all plugins for each translation
667        on the page into the respective translation in the new page.
668        """
669        languages = ('en', 'de', 'fr', 'pt-br')
670        cms_page = create_page("page_a_en", "nav_playground.html", "en")
671        create_title('de', 'page_a_de', cms_page)
672        create_title('fr', 'page_a_fr', cms_page)
673        create_title('pt-br', 'page_a_pt-br', cms_page)
674        placeholder = cms_page.placeholders.get(slot='body')
675
676        for language in languages:
677            add_plugin(
678                placeholder,
679                plugin_type='LinkPlugin',
680                language=language,
681                name='Link {}'.format(language),
682                external_link='https://www.django-cms.org',
683            )
684
685        with self.login_user_context(self.get_superuser()):
686            new_page = self.copy_page(cms_page, cms_page, position=1)
687            new_placeholder = new_page.placeholders.get(slot='body')
688
689        for language in languages:
690            self.assertTrue(new_placeholder.get_plugins(language).exists())
691            plugin = new_placeholder.get_plugins(language)[0].get_bound_plugin()
692            self.assertEqual(plugin.name, 'Link {}'.format(language))
693
694    def test_copy_page_to_root(self):
695        """
696        When a page is copied and its slug matches that of another page,
697        add "-copy-2" at the end.
698        """
699        data = {
700            'position': 2,
701            'source_site': 1,
702            'copy_permissions': 'on',
703            'copy_moderation': 'on',
704        }
705        superuser = self.get_superuser()
706        cms_page = create_page("page_a", "nav_playground.html", "en", published=True)
707
708        with self.login_user_context(superuser):
709            endpoint = self.get_admin_url(Page, 'copy_page', cms_page.pk)
710            response = self.client.post(endpoint, data)
711            self.assertEqual(response.status_code, 200)
712
713        new_slug = cms_page.get_path('en') + '-copy-2'
714        new_path = cms_page.get_slug('en') + '-copy-2'
715
716        self.assertEqual(
717            Title.objects.filter(slug=new_slug, path=new_path).count(),
718            1,
719        )
720
721    def test_copy_page_to_root_with_pagetypes(self):
722        """
723        When a page is copied, the cms should not count page types
724        when calculating where the sibling node of the new page.
725        """
726        data = {
727            'position': 4,
728            'source_site': 1,
729            'copy_permissions': 'on',
730            'copy_moderation': 'on',
731        }
732        superuser = self.get_superuser()
733        page_1 = create_page("page_a", "nav_playground.html", "en", published=True)
734        page_2 = create_page("page_b", "nav_playground.html", "en", published=True)
735
736        with self.login_user_context(superuser):
737            # Creates a page type whose nodes will be in the middle
738            # of other page nodes.
739            self.client.post(
740                self.get_admin_url(PageType, 'add'),
741                data={'source': page_1.pk, 'title': 'type1', 'slug': 'type1', '_save': 1},
742            )
743            self.client.post(
744                self.get_admin_url(PageType, 'add'),
745                data={'source': page_1.pk, 'title': 'type2', 'slug': 'type2', '_save': 1},
746            )
747            page_type_0 = self.assertObjectExist(
748                Page.objects.all(),
749                is_page_type=True,
750                node__parent__isnull=True,
751                publisher_is_draft=True,
752            )
753            page_type_1 = self.assertObjectExist(
754                Page.objects.all(),
755                is_page_type=True,
756                title_set__slug='type1',
757                publisher_is_draft=True,
758            )
759            page_type_2 = self.assertObjectExist(
760                Page.objects.all(),
761                is_page_type=True,
762                title_set__slug='type2',
763                publisher_is_draft=True,
764            )
765
766            # Add some normal pages on top of the page type nodes
767            page_3 = create_page("page_c", "nav_playground.html", "en", published=True)
768            page_4 = create_page("page_d", "nav_playground.html", "en", published=True)
769
770            # Copy a page and insert it at the bottom of all pages
771            endpoint = self.get_admin_url(Page, 'copy_page', page_1.pk)
772            response = self.client.post(endpoint, data)
773            self.assertEqual(response.status_code, 200)
774
775        new_slug = page_1.get_path('en') + '-copy-2'
776        new_path = page_1.get_slug('en') + '-copy-2'
777
778        page_5_title = self.assertObjectExist(
779            Title.objects.all(),
780            slug=new_slug,
781            path=new_path,
782        )
783        page_5 = page_5_title.page
784
785        tree = (
786            (page_1, '0001'),
787            (page_2, '0002'),
788            (page_type_0, '0003'),
789            (page_type_1, '00030001'),
790            (page_type_2, '00030002'),
791            (page_3, '0004'),
792            (page_4, '0005'),
793            (page_5, '0006'),
794        )
795
796        for page, path in tree:
797            self.assertEqual(self.reload(page.node).path, path)
798
799    def test_copy_page_to_different_site(self):
800        superuser = self.get_superuser()
801        site_2 = Site.objects.create(id=2, domain='example-2.com', name='example-2.com')
802        site_1_root = create_page("site 1 root", "nav_playground.html", "de", published=True)
803        site_2_parent = create_page("parent", "nav_playground.html", "de", published=True, site=site_2)
804        child_0002 = create_page(
805            "child-0002",
806            template="nav_playground.html",
807            language="de",
808            published=True,
809            parent=site_2_parent,
810            site=site_2,
811        )
812        child_0003 = create_page(
813            "child-0003",
814            template="nav_playground.html",
815            language="de",
816            published=True,
817            parent=site_2_parent,
818            site=site_2,
819        )
820        child_0005 = create_page(
821            "child-0005",
822            template="nav_playground.html",
823            language="de",
824            published=True,
825            parent=site_2_parent,
826            site=site_2,
827        )
828
829        with self.login_user_context(superuser):
830            # Copy the root page from site 1 and insert it as first child
831            # of the site 2 parent.
832            child_0001 = self.copy_page(site_1_root, site_2_parent, position=0)
833
834        with self.login_user_context(superuser):
835            # Copy the root page from site 1 and insert it as fourth child
836            # of the site 2 parent.
837            child_0004 = self.copy_page(site_1_root, site_2_parent, position=3)
838
839        tree = (
840            (site_2_parent, '0002'),
841            (child_0001, '00020001'),
842            (child_0002, '00020002'),
843            (child_0003, '00020003'),
844            (child_0004, '00020004'),
845            (child_0005, '00020005'),
846        )
847
848        for page, path in tree:
849            node = self.reload(page.node)
850            self.assertEqual(node.path, path)
851            self.assertEqual(node.site_id, 2)
852
853    def test_copy_page_to_different_site_fails_with_untranslated_page(self):
854        data = {
855            'position': 0,
856            'source_site': 1,
857            'copy_permissions': 'on',
858            'copy_moderation': 'on',
859        }
860        superuser = self.get_superuser()
861        site_2 = Site.objects.create(id=2, domain='example-2.com', name='example-2.com')
862        site_1_root = create_page("site 1 root", "nav_playground.html", "en", published=True)
863        expected_response = {
864            "status": 400,
865            "content": "Error! The page you're pasting is not translated in "
866                       "any of the languages configured by the target site.",
867        }
868
869        with self.settings(SITE_ID=2):
870            with self.login_user_context(superuser):
871                # Simulate the copy-dialog
872                endpoint = self.get_admin_url(Page, 'get_copy_dialog', site_1_root.pk)
873                endpoint += '?source_site=%s' % site_1_root.node.site_id
874                response = self.client.get(endpoint)
875                self.assertEqual(response.status_code, 200)
876
877                # Copy the root page from site 1 and insert it as the first root page
878                # on site 2.
879                endpoint = self.get_admin_url(Page, 'copy_page', site_1_root.pk)
880                response = self.client.post(endpoint, data)
881                self.assertEqual(response.status_code, 200)
882                self.assertObjectDoesNotExist(Page.objects.all(), node__site=site_2)
883                self.assertEqual(
884                    json.loads(response.content.decode('utf8')),
885                    expected_response,
886                )
887
888    def test_copy_page_to_different_site_with_no_pages(self):
889        data = {
890            'position': 0,
891            'source_site': 1,
892            'copy_permissions': 'on',
893            'copy_moderation': 'on',
894        }
895        superuser = self.get_superuser()
896        site_2 = Site.objects.create(id=2, domain='example-2.com', name='example-2.com')
897        site_1_root = create_page("site 1 root", "nav_playground.html", "de", published=True)
898
899        with self.settings(SITE_ID=2):
900            with self.login_user_context(superuser):
901                # Simulate the copy-dialog
902                endpoint = self.get_admin_url(Page, 'get_copy_dialog', site_1_root.pk)
903                endpoint += '?source_site=%s' % site_1_root.node.site_id
904                response = self.client.get(endpoint)
905                self.assertEqual(response.status_code, 200)
906
907                # Copy the root page from site 1 and insert it as the first root page
908                # on site 2.
909                endpoint = self.get_admin_url(Page, 'copy_page', site_1_root.pk)
910                response = self.client.post(endpoint, data)
911                self.assertEqual(response.status_code, 200)
912
913        site_2_root = self.assertObjectExist(Page.objects.drafts(), node__site=site_2)
914
915        tree = (
916            (site_1_root, '0001'),
917            (site_2_root, '0002'),
918        )
919
920        for page, path in tree:
921            self.assertEqual(self.reload(page.node).path, path)
922
923    def test_copy_page_to_explicit_position(self):
924        """
925        User should be able to copy a single page and paste it
926        in a specific location on another page tree.
927        """
928        superuser = self.get_superuser()
929        parent = create_page("parent", "nav_playground.html", "en", published=True)
930        child_0002 = create_page("child-0002", "nav_playground.html", "en", published=True, parent=parent)
931        child_0003 = create_page("child-0003", "nav_playground.html", "en", published=True, parent=parent)
932        child_0005 = create_page("child-0005", "nav_playground.html", "en", published=True, parent=parent)
933        child_0004 = create_page("child-0004", "nav_playground.html", "en", published=True)
934
935        with self.login_user_context(superuser):
936            # Copy the 0005 page and insert it as first child of parent
937            child_0001 = self.copy_page(child_0005, parent, position=0)
938
939        with self.login_user_context(superuser):
940            # Copy the 0004 page and insert it as fourth child of parent
941            child_0004 = self.copy_page(child_0004, parent, position=3)
942
943        tree = (
944            (parent, '0001'),
945            (child_0001, '00010001'),
946            (child_0002, '00010002'),
947            (child_0003, '00010003'),
948            (child_0004, '00010004'),
949            (child_0005, '00010005'),
950        )
951
952        for page, path in tree:
953            self.assertEqual(self.reload(page.node).path, path)
954
955    def test_copy_page_tree_to_explicit_position(self):
956        """
957        User should be able to copy a page with descendants and paste it
958        in a specific location on another page tree.
959        """
960        superuser = self.get_superuser()
961        parent = create_page("parent", "nav_playground.html", "en", published=True)
962        child_0002 = create_page("child-0002", "nav_playground.html", "en", published=True, parent=parent)
963        child_0003 = create_page("child-0003", "nav_playground.html", "en", published=True, parent=parent)
964        child_0005 = create_page("child-0005", "nav_playground.html", "en", published=True, parent=parent)
965        create_page("child-00050001", "nav_playground.html", "en", published=True, parent=child_0005)
966        create_page("child-00050002", "nav_playground.html", "en", published=True, parent=child_0005)
967        create_page("child-00050003", "nav_playground.html", "en", published=True, parent=child_0005)
968        child_0004 = create_page("child-0004", "nav_playground.html", "en", published=True)
969        create_page("child-00040001", "nav_playground.html", "en", published=True, parent=child_0004)
970        create_page("child-00040002", "nav_playground.html", "en", published=True, parent=child_0004)
971        create_page("child-00040003", "nav_playground.html", "en", published=True, parent=child_0004)
972
973        with self.login_user_context(superuser):
974            # Copy the 0005 page and insert it as first child of parent
975            child_0001 = self.copy_page(child_0005, parent, position=0)
976            child_pages = list(child_0001.get_child_pages())
977            child_00010001 = child_pages[0]
978            child_00010002 = child_pages[1]
979            child_00010003 = child_pages[2]
980
981        with self.login_user_context(superuser):
982            # Copy the 0004 page and insert it as fourth child of parent
983            child_0004 = self.copy_page(child_0004, parent, position=3)
984            child_pages = list(child_0004.get_child_pages())
985            child_00040001 = child_pages[0]
986            child_00040002 = child_pages[1]
987            child_00040003 = child_pages[2]
988
989        tree = (
990            (parent, '0001'),
991            (child_0001, '00010001'),
992            (child_00010001, '000100010001'),
993            (child_00010002, '000100010002'),
994            (child_00010003, '000100010003'),
995            (child_0002, '00010002'),
996            (child_0003, '00010003'),
997            (child_0004, '00010004'),
998            (child_00040001, '000100040001'),
999            (child_00040002, '000100040002'),
1000            (child_00040003, '000100040003'),
1001            (child_0005, '00010005'),
1002        )
1003
1004        for page, path in tree:
1005            self.assertEqual(self.reload(page.node).path, path)
1006
1007    def test_copy_self_page(self):
1008        """
1009        Test that a page can be copied via the admin
1010        """
1011        page_a = create_page("page_a", "nav_playground.html", "en")
1012        page_b = create_page("page_b", "nav_playground.html", "en", parent=page_a)
1013        page_c = create_page("page_c", "nav_playground.html", "en", parent=page_b)
1014        with self.login_user_context(self.get_superuser()):
1015            self.copy_page(page_b, page_b, position=1)
1016        self.assertEqual(Page.objects.drafts().count(), 5)
1017        self.assertEqual(page_b.get_child_pages().count(), 2)
1018        page_d = page_b.get_child_pages()[1]
1019        page_e = page_d.get_child_pages()[0]
1020        self.assertEqual(page_d.node.path, '000100010002')
1021        self.assertEqual(page_e.node.path, '0001000100020001')
1022        page_e.delete()
1023        page_d.delete()
1024        with self.login_user_context(self.get_superuser()):
1025            self.copy_page(page_b, page_c)
1026        self.assertEqual(page_c.get_child_pages().count(), 1)
1027        self.assertEqual(page_b.get_child_pages().count(), 1)
1028        page_ids = list(page_c.get_descendant_pages().values_list('pk', flat=True))
1029        page_c.get_descendant_pages().delete()
1030        Page.objects.filter(pk__in=page_ids).delete()
1031        self.assertEqual(Page.objects.all().count(), 3)
1032        page_b = page_b.reload()
1033        page_c = page_c.reload()
1034        with self.login_user_context(self.get_superuser()):
1035            self.copy_page(page_b, page_c, position=0)
1036
1037    def test_get_admin_tree_title(self):
1038        page = create_page("page_a", "nav_playground.html", "en", published=True)
1039        self.assertEqual(page.get_admin_tree_title(), 'page_a')
1040        languages = {
1041            1: [
1042                {
1043                    'code': 'en',
1044                    'name': 'English',
1045                    'fallbacks': ['fr', 'de'],
1046                    'public': True,
1047                    'fallbacks': ['fr']
1048                },
1049                {
1050                    'code': 'fr',
1051                    'name': 'French',
1052                    'public': True,
1053                    'fallbacks': ['en']
1054                },
1055        ]}
1056        with self.settings(CMS_LANGUAGES=languages):
1057            with force_language('fr'):
1058                page.title_cache = {'en': Title(slug='test', page_title="test2", title="test2")}
1059                self.assertEqual('test2', force_text(page.get_admin_tree_title()))
1060                page.title_cache = {'en': Title(slug='test', page_title="test2")}
1061                self.assertEqual('test2', force_text(page.get_admin_tree_title()))
1062                page.title_cache = {'en': Title(slug='test', menu_title="test2")}
1063                self.assertEqual('test2', force_text(page.get_admin_tree_title()))
1064                page.title_cache = {'en': Title(slug='test2')}
1065                self.assertEqual('test2', force_text(page.get_admin_tree_title()))
1066                page.title_cache = {'en': Title(slug='test2'), 'fr': EmptyTitle('fr')}
1067                self.assertEqual('test2', force_text(page.get_admin_tree_title()))
1068
1069    def test_language_change(self):
1070        superuser = self.get_superuser()
1071        with self.login_user_context(superuser):
1072            page_data = self.get_new_page_data()
1073            self.client.post(URL_CMS_PAGE_ADD, page_data)
1074            pk = Page.objects.drafts().first().pk
1075            response = self.client.get(URL_CMS_PAGE_CHANGE % pk, {"language": "en"})
1076            self.assertEqual(response.status_code, 200)
1077            response = self.client.get(URL_CMS_PAGE_CHANGE % pk, {"language": "de"})
1078            self.assertEqual(response.status_code, 200)
1079
1080    def test_move_page(self):
1081        superuser = self.get_superuser()
1082        with self.login_user_context(superuser):
1083            page_home = self.get_new_page_data()
1084            self.client.post(URL_CMS_PAGE_ADD, page_home)
1085            page_data1 = self.get_new_page_data()
1086            self.client.post(URL_CMS_PAGE_ADD, page_data1)
1087            page_data2 = self.get_new_page_data()
1088            self.client.post(URL_CMS_PAGE_ADD, page_data2)
1089            page_data3 = self.get_new_page_data()
1090            self.client.post(URL_CMS_PAGE_ADD, page_data3)
1091            pages = list(Page.objects.drafts().order_by('node__path'))
1092            home = pages[0]
1093            page1 = pages[1]
1094            page2 = pages[2]
1095            page3 = pages[3]
1096
1097            # move pages
1098            response = self.client.post(URL_CMS_PAGE_MOVE % page3.pk, {"target": page2.pk, "position": "0"})
1099            self.assertEqual(response.status_code, 200)
1100
1101            page3 = Page.objects.get(pk=page3.pk)
1102            response = self.client.post(URL_CMS_PAGE_MOVE % page2.pk, {"target": page1.pk, "position": "0"})
1103            self.assertEqual(response.status_code, 200)
1104            # check page2 path and url
1105            page2 = Page.objects.get(pk=page2.pk)
1106            self.assertEqual(page2.get_path(), page_data1['slug'] + "/" + page_data2['slug'])
1107            self.assertEqual(page2.get_absolute_url(),
1108                             self.get_pages_root() + page_data1['slug'] + "/" + page_data2['slug'] + "/")
1109            # check page3 path and url
1110            page3 = Page.objects.get(pk=page3.pk)
1111            self.assertEqual(page3.get_path(), page_data1['slug'] + "/" + page_data2['slug'] + "/" + page_data3['slug'])
1112            self.assertEqual(page3.get_absolute_url(),
1113                             self.get_pages_root() + page_data1['slug'] + "/" + page_data2['slug'] + "/" + page_data3[
1114                                 'slug'] + "/")
1115
1116            # Remove home page
1117            home.delete()
1118
1119            # Publish page1
1120            page1.publish('en')
1121
1122            # Promote page1 to be the new homepage
1123            page1.set_as_homepage()
1124            self.assertEqual(page1.get_path(), '')
1125            self.assertEqual(page1.publisher_public.reload().get_path(), '')
1126            # check that page2 and page3 url have changed
1127            page2 = Page.objects.get(pk=page2.pk)
1128            page2.publish('en')
1129            public_page2 = page2.publisher_public
1130            self.assertEqual(public_page2.get_absolute_url(), self.get_pages_root() + page_data2['slug'] + "/")
1131            page3 = Page.objects.get(pk=page3.pk)
1132            page3.publish('en')
1133            public_page3 = page3.publisher_public
1134            self.assertEqual(public_page3.get_absolute_url(),
1135                             self.get_pages_root() + page_data2['slug'] + "/" + page_data3['slug'] + "/")
1136            # set page2 as root and check path of 1 and 3
1137            response = self.client.post(URL_CMS_PAGE_MOVE % page2.pk,
1138                                        {"position": "0"})
1139            self.assertEqual(response.status_code, 200)
1140            page1 = Page.objects.get(pk=page1.pk)
1141            self.assertEqual(page1.get_path(), '')
1142            page2 = Page.objects.get(pk=page2.pk)
1143            self.assertFalse(page2.is_home)
1144            self.assertEqual(page2.get_path(), page_data2['slug'])
1145            page3 = Page.objects.get(pk=page3.pk)
1146            self.assertEqual(page3.get_path(), page_data2['slug'] + "/" + page_data3['slug'])
1147
1148    def test_user_cant_nest_home_page(self):
1149        """
1150        Users should not be able to move the home-page
1151        inside another node of the tree.
1152        """
1153        homepage = create_page("home", "nav_playground.html", "en", published=True)
1154        homepage.set_as_homepage()
1155        home_sibling_1 = create_page("root-1", "nav_playground.html", "en", published=True)
1156
1157        payload = {'id': homepage.pk, 'position': 0, 'target': home_sibling_1}
1158
1159        with self.login_user_context(self.get_superuser()):
1160            endpoint = self.get_admin_url(Page, 'move_page', homepage.pk)
1161            response = self.client.post(endpoint, payload)
1162
1163            self.assertEqual(response.status_code, 200)
1164            self.assertEqual(response.json().get('status', 400), 400)
1165
1166    def test_move_home_page(self):
1167        """
1168        Users should be able to move the home-page
1169        anywhere on the root of the tree.
1170        """
1171        homepage = create_page("home", "nav_playground.html", "en", published=True)
1172        homepage.set_as_homepage()
1173        home_child_1 = create_page(
1174            "child-1",
1175            "nav_playground.html",
1176            language="en",
1177            parent=homepage,
1178            published=True,
1179        )
1180        home_child_2 = create_page(
1181            "child-2",
1182            "nav_playground.html",
1183            language="en",
1184            parent=homepage,
1185            published=True,
1186        )
1187        home_sibling_1 = create_page("root-1", "nav_playground.html", "en", published=True)
1188
1189        expected_tree = [
1190            # Sadly treebeard doesn't switch the paths
1191            (home_sibling_1, '0002', 'root-1'),
1192            (homepage, '0003', ''),
1193            (home_child_1, '00030001', 'child-1'),
1194            (home_child_2, '00030002', 'child-2'),
1195        ]
1196
1197        with self.login_user_context(self.get_superuser()):
1198            # Moves the homepage to the second position in the tree
1199            data = {'id': homepage.pk, 'position': 1}
1200            endpoint = self.get_admin_url(Page, 'move_page', homepage.pk)
1201            response = self.client.post(endpoint, data)
1202            self.assertEqual(response.status_code, 200)
1203
1204            for page, node_path, url_path in expected_tree:
1205                page._clear_internal_cache()
1206                self.assertEqual(page.node.path, node_path)
1207                self.assertEqual(page.get_path('en'), url_path)
1208                self.assertEqual(page.publisher_public.get_path('en'), url_path)
1209
1210    def test_move_page_integrity(self):
1211        superuser = self.get_superuser()
1212        with self.login_user_context(superuser):
1213            page_home = self.get_new_page_data()
1214            self.client.post(URL_CMS_PAGE_ADD, page_home)
1215
1216            # Create parent page
1217            page_root = create_page("Parent", 'col_three.html', "en")
1218            page_root.publish('en')
1219
1220            # Create child pages
1221            page_child_1 = create_page(
1222                "Child 1",
1223                template=constants.TEMPLATE_INHERITANCE_MAGIC,
1224                language="en",
1225                parent=page_root,
1226            )
1227            page_child_1.publish('en')
1228
1229            page_child_2 = create_page(
1230                "Child 2",
1231                template=constants.TEMPLATE_INHERITANCE_MAGIC,
1232                language="en",
1233                parent=page_root,
1234            )
1235            page_child_2.publish('en')
1236
1237            # Create two root pages that ware meant as child pages
1238            page_child_3 = create_page("Child 3", 'col_three.html', "en")
1239            page_child_4 = create_page("Child 4", 'col_three.html', "en", published=True)
1240
1241            # Correct our mistake.
1242            # Move page_child_3 to be child of parent page
1243            data = {
1244                "id": page_child_3.pk,
1245                "target": page_root.pk,
1246                "position": "0",
1247            }
1248            response = self.client.post(
1249                URL_CMS_PAGE_MOVE % page_child_3.pk,
1250                data,
1251            )
1252            self.assertEqual(response.status_code, 200)
1253
1254            # Un-publish page_child_4
1255            page_child_4.unpublish('en')
1256
1257            # Move page_child_4 to be child of parent page
1258            data = {
1259                "id": page_child_4.pk,
1260                "target": page_root.pk,
1261                "position": "0",
1262            }
1263            response = self.client.post(
1264                URL_CMS_PAGE_MOVE % page_child_4.pk,
1265                data,
1266            )
1267            self.assertEqual(response.status_code, 200)
1268
1269            page_root = page_root.reload()
1270            page_child_4 = page_child_4.reload()
1271
1272            # Ensure move worked
1273            self.assertEqual(page_root.node.get_descendants().count(), 4)
1274
1275            # Ensure page_child_3 is still unpublished
1276            self.assertEqual(
1277                page_child_3.get_publisher_state("en"),
1278                PUBLISHER_STATE_DIRTY
1279            )
1280            self.assertEqual(page_child_3.is_published("en"), False)
1281
1282            # Ensure page_child_4 is still unpublished
1283            self.assertEqual(
1284                page_child_4.get_publisher_state("en"),
1285                PUBLISHER_STATE_DIRTY
1286            )
1287            self.assertEqual(page_child_4.is_published("en"), False)
1288
1289            # And it's public page is still has the published state
1290            # but is marked as unpublished
1291            self.assertEqual(
1292                page_child_4.publisher_public.get_publisher_state("en"),
1293                PUBLISHER_STATE_DEFAULT
1294            )
1295            self.assertEqual(
1296                page_child_4.publisher_public.is_published("en"),
1297                False,
1298            )
1299
1300            # Ensure child one is still published
1301            self.assertEqual(
1302                page_child_1.get_publisher_state("en"),
1303                PUBLISHER_STATE_DEFAULT
1304            )
1305            self.assertEqual(page_child_1.is_published("en"), True)
1306
1307            # Ensure child two is still published
1308            self.assertEqual(
1309                page_child_2.get_publisher_state("en"),
1310                PUBLISHER_STATE_DEFAULT
1311            )
1312            self.assertEqual(page_child_2.is_published("en"), True)
1313
1314    def test_edit_page_other_site_and_language(self):
1315        """
1316        Test that a page can edited via the admin when your current site is
1317        different from the site you are editing and the language isn't available
1318        for the current site.
1319        """
1320        self.assertEqual(Site.objects.all().count(), 1)
1321        site = Site.objects.create(domain='otherlang', name='otherlang', pk=2)
1322        # Change site for this session
1323        page_data = self.get_new_page_data()
1324        page_data['site'] = site.pk
1325        page_data['title'] = 'changed title'
1326        self.assertEqual(site.pk, 2)
1327        TESTLANG = get_cms_setting('LANGUAGES')[site.pk][0]['code']
1328        page_data['language'] = TESTLANG
1329        superuser = self.get_superuser()
1330        with self.login_user_context(superuser):
1331            response = self.client.post(URL_CMS_PAGE_ADD, page_data)
1332            self.assertRedirects(response, URL_CMS_PAGE)
1333            page = Page.objects.get(title_set__slug=page_data['slug'], publisher_is_draft=True)
1334            with LanguageOverride(TESTLANG):
1335                self.assertEqual(page.get_title(), 'changed title')
1336
1337    def test_get_page_from_request_cached(self):
1338        mock_page = 'hello world'
1339        request = self.get_request(
1340            admin_reverse('sampleapp_category_change', args=(1,))
1341        )
1342        request._current_page_cache = mock_page
1343        page = get_page_from_request(request)
1344        self.assertEqual(page, mock_page)
1345
1346    @override_settings(CMS_PERMISSION=False)
1347    def test_set_overwrite_url(self):
1348        superuser = self.get_superuser()
1349        cms_page = create_page('page', 'nav_playground.html', 'en', published=True)
1350        expected = (
1351            '<input id="id_overwrite_url" maxlength="255" '
1352            'value="new-url" name="overwrite_url" type="text" />'
1353        )
1354        changelist = self.get_admin_url(Page, 'changelist')
1355        endpoint = self.get_admin_url(Page, 'advanced', cms_page.pk)
1356
1357        with self.login_user_context(superuser):
1358            page_data = {
1359                'overwrite_url': '/new-url/',
1360                'template': cms_page.template,
1361            }
1362            response = self.client.post(endpoint, page_data)
1363            self.assertRedirects(response, changelist)
1364
1365        with self.login_user_context(superuser):
1366            response = self.client.get(endpoint)
1367            self.assertContains(response, expected, html=True)
1368
1369    @override_settings(CMS_PERMISSION=False)
1370    def test_set_existing_overwrite_url(self):
1371        superuser = self.get_superuser()
1372
1373        create_page('home', 'nav_playground.html', 'en', published=True)
1374        boo = create_page('boo', 'nav_playground.html', 'en', published=True)
1375        hoo = create_page('hoo', 'nav_playground.html', 'en', published=True)
1376        expected_error = (
1377            '<ul class="errorlist"><li>Page '
1378            '<a href="{}" target="_blank">boo</a> '
1379            'has the same url \'boo\' as current page "hoo".</li></ul>'
1380        ).format(self.get_admin_url(Page, 'change', boo.pk))
1381
1382        with self.login_user_context(superuser):
1383            endpoint = self.get_admin_url(Page, 'advanced', hoo.pk)
1384            page_data = {
1385                'overwrite_url': '/boo/',
1386                'template': hoo.template,
1387            }
1388            response = self.client.post(endpoint, page_data)
1389            self.assertEqual(response.status_code, 200)
1390            self.assertContains(response, expected_error, html=True)
1391
1392    @override_settings(CMS_PERMISSION=False)
1393    def test_remove_overwrite_url(self):
1394        superuser = self.get_superuser()
1395        cms_page = create_page(
1396            'page',
1397            'nav_playground.html',
1398            language='en',
1399            published=True,
1400            overwrite_url='/new-url/',
1401        )
1402        expected = (
1403            '<input id="id_overwrite_url" maxlength="255" '
1404            'name="overwrite_url" type="text" />'
1405        )
1406        changelist = self.get_admin_url(Page, 'changelist')
1407        endpoint = self.get_admin_url(Page, 'advanced', cms_page.pk)
1408
1409        # control test
1410        self.assertTrue(cms_page.title_set.filter(path='new-url').exists())
1411
1412        with self.login_user_context(superuser):
1413            page_data = {
1414                'overwrite_url': '',
1415                'template': cms_page.template,
1416            }
1417            response = self.client.post(endpoint, page_data)
1418            self.assertRedirects(response, changelist)
1419
1420        with self.login_user_context(superuser):
1421            response = self.client.get(endpoint)
1422            self.assertContains(response, expected, html=True)
1423
1424    @override_settings(CMS_PERMISSION=False)
1425    def test_rewrite_url_being_corrupted_after_save_basic_settings(self):
1426        superuser = self.get_superuser()
1427        parent_page = create_page(
1428            'parent',
1429            'nav_playground.html',
1430            language='en',
1431            published=True,
1432        )
1433        child_page = create_page(
1434            'child',
1435            'nav_playground.html',
1436            language='en',
1437            published=True,
1438            parent=parent_page,
1439        )
1440
1441        with self.login_user_context(superuser):
1442            endpoint = self.get_admin_url(Page, 'advanced', child_page.pk)
1443            self.client.post(
1444                endpoint,
1445                {
1446                    'overwrite_url': 'rewrited',
1447                    'template': child_page.template,
1448                },
1449            )
1450            child_page.publish('en')
1451
1452            endpoint = self.get_admin_url(Page, 'change', child_page.pk)
1453            self.client.post(
1454                endpoint,
1455                {
1456                    'language': 'en',
1457                    'title': 'child',
1458                    'slug': 'child',
1459                },
1460            )
1461
1462        title = child_page.get_title_obj('en', fallback=False)
1463        self.assertEqual(title.path, 'rewrited')
1464
1465    def test_advanced_settings_form(self):
1466        superuser = self.get_superuser()
1467        page = create_page('Page 1', 'nav_playground.html', 'en')
1468        endpoint = self.get_admin_url(Page, 'advanced', page.pk)
1469
1470        # First we provide fully valid conditions to make sure
1471        # the form is working.
1472        page_data = {
1473            'template': 'col_two.html',
1474        }
1475
1476        with self.login_user_context(superuser):
1477            redirect_to = self.get_admin_url(Page, 'change', page.pk) + '?language=de'
1478            # Add german as the current language
1479            # Note that german has not been created as page translation.
1480            response = self.client.post(endpoint + '?language=de', page_data, follow=True)
1481            self.assertRedirects(response, redirect_to)
1482            self.assertEqual(
1483                [m.message for m in response.context['messages']],
1484                ["Please create the German page translation before editing it's advanced settings."]
1485            )
1486
1487        de_translation = create_title('de', title='Page 1', page=page)
1488        de_translation.slug = ''
1489        de_translation.save()
1490
1491        # First make sure the title has no slug
1492        self.assertEqual(de_translation.slug, '')
1493
1494        expected_error = (
1495            '<ul class="errorlist">'
1496            '<li>Please set the German slug before editing its advanced settings.</li></ul>'
1497        )
1498
1499        with self.login_user_context(superuser):
1500            response = self.client.post(endpoint + '?language=de', page_data)
1501            self.assertEqual(response.status_code, 200)
1502            self.assertContains(response, expected_error)
1503
1504    def test_advanced_settings_form_apphook(self):
1505        superuser = self.get_superuser()
1506        cms_page = create_page('app', 'nav_playground.html', 'en', published=True)
1507        cms_pages = Page.objects.filter(pk__in=[cms_page.pk, cms_page.publisher_public_id])
1508        redirect_to = self.get_admin_url(Page, 'changelist')
1509        endpoint = self.get_admin_url(Page, 'advanced', cms_page.pk)
1510        page_data = {
1511            "redirect": "",
1512            "language": "en",
1513            "reverse_id": "",
1514            "navigation_extenders": "",
1515            "site": "1",
1516            "xframe_options": "0",
1517            "application_urls": "SampleApp",
1518            "application_namespace": "sampleapp",
1519            "overwrite_url": "",
1520            "template": "INHERIT",
1521        }
1522
1523        with self.login_user_context(superuser):
1524            # set the apphook
1525            response = self.client.post(endpoint, page_data)
1526            self.assertRedirects(response, redirect_to)
1527            self.assertEqual(
1528                cms_pages.filter(
1529                    application_urls='SampleApp',
1530                    application_namespace='sampleapp',
1531                ).count(),
1532                2
1533            )
1534
1535        with self.login_user_context(superuser):
1536            # remove the apphook
1537            page_data['application_urls'] = ''
1538            page_data['application_namespace'] = ''
1539            response = self.client.post(endpoint, page_data)
1540            self.assertRedirects(response, redirect_to)
1541            self.assertEqual(
1542                cms_pages.filter(
1543                    application_urls='',
1544                    application_namespace=None,
1545                ).count(),
1546                2,
1547            )
1548
1549    @override_settings(CMS_APPHOOKS=[
1550        'cms.test_utils.project.sampleapp.cms_apps.SampleApp',
1551        'cms.test_utils.project.sampleapp.cms_apps.SampleAppWithConfig',
1552    ])
1553    def test_advanced_settings_form_apphook_config(self):
1554        clear_app_resolvers()
1555        clear_url_caches()
1556
1557        if 'cms.test_utils.project.sampleapp.cms_apps' in sys.modules:
1558            del sys.modules['cms.test_utils.project.sampleapp.cms_apps']
1559
1560        self.apphook_clear()
1561
1562        superuser = self.get_superuser()
1563        app_config = SampleAppConfig.objects.create(namespace='sample')
1564        cms_page = create_page('app', 'nav_playground.html', 'en', published=True)
1565        cms_pages = Page.objects.filter(pk__in=[cms_page.pk, cms_page.publisher_public_id])
1566        redirect_to = self.get_admin_url(Page, 'changelist')
1567        endpoint = self.get_admin_url(Page, 'advanced', cms_page.pk)
1568        page_data = {
1569            "redirect": "",
1570            "language": "en",
1571            "reverse_id": "",
1572            "navigation_extenders": "",
1573            "site": "1",
1574            "xframe_options": "0",
1575            "application_urls": "SampleAppWithConfig",
1576            "application_configs": app_config.pk,
1577            "application_namespace": "sampleapp",
1578            "overwrite_url": "",
1579            "template": "INHERIT",
1580        }
1581
1582        with self.login_user_context(superuser):
1583            # set the apphook config
1584            response = self.client.post(endpoint, page_data)
1585            self.assertRedirects(response, redirect_to)
1586            self.assertEqual(
1587                cms_pages.filter(
1588                    application_urls='SampleAppWithConfig',
1589                    application_namespace=app_config.namespace,
1590                ).count(),
1591                2
1592            )
1593
1594        with self.login_user_context(superuser):
1595            # change from apphook with config to normal apphook
1596            page_data['application_urls'] = 'SampleApp'
1597            page_data['application_namespace'] = 'sampleapp'
1598            response = self.client.post(endpoint, page_data)
1599            self.assertRedirects(response, redirect_to)
1600            self.assertEqual(
1601                cms_pages.filter(
1602                    application_urls='SampleApp',
1603                    application_namespace='sampleapp',
1604                ).count(),
1605                2
1606            )
1607
1608        with self.login_user_context(superuser):
1609            # set the apphook config again
1610            page_data['application_urls'] = 'SampleAppWithConfig'
1611            page_data['application_namespace'] = 'sampleapp'
1612            response = self.client.post(endpoint, page_data)
1613            self.assertRedirects(response, redirect_to)
1614            self.assertEqual(
1615                cms_pages.filter(
1616                    application_urls='SampleAppWithConfig',
1617                    application_namespace=app_config.namespace,
1618                ).count(),
1619                2
1620            )
1621
1622        with self.login_user_context(superuser):
1623            # change the apphook config to an invalid value
1624            expected_error = '<ul class="errorlist"><li>Invalid application config value</li></ul>'
1625            page_data['application_configs'] = '2'
1626            response = self.client.post(endpoint, page_data)
1627            self.assertEqual(response.status_code, 200)
1628            self.assertContains(response, expected_error)
1629            self.assertEqual(
1630                cms_pages.filter(
1631                    application_urls='SampleAppWithConfig',
1632                    application_namespace=app_config.namespace,
1633                ).count(),
1634                2
1635            )
1636
1637        with self.login_user_context(superuser):
1638            # remove the apphook
1639            page_data['application_urls'] = ''
1640            page_data['application_namespace'] = ''
1641            response = self.client.post(endpoint, page_data)
1642            self.assertRedirects(response, redirect_to)
1643            self.assertEqual(
1644                cms_pages.filter(
1645                    application_urls='',
1646                    application_namespace=None,
1647                ).count(),
1648                2,
1649            )
1650        clear_app_resolvers()
1651        clear_url_caches()
1652
1653        if 'cms.test_utils.project.sampleapp.cms_apps' in sys.modules:
1654            del sys.modules['cms.test_utils.project.sampleapp.cms_apps']
1655        self.apphook_clear()
1656
1657    def test_form_url_page_change(self):
1658        superuser = self.get_superuser()
1659        with self.login_user_context(superuser):
1660            pageadmin = self.get_admin()
1661            page = self.get_page()
1662            form_url = admin_reverse("cms_page_change", args=(page.pk,))
1663            # Middleware is needed to correctly setup the environment for the admin
1664            middleware = CurrentUserMiddleware()
1665            request = self.get_request()
1666            middleware.process_request(request)
1667            response = pageadmin.change_view(
1668                request, str(page.pk),
1669                form_url=form_url)
1670            self.assertTrue('form_url' in response.context_data)
1671            self.assertEqual(response.context_data['form_url'], form_url)
1672
1673    def _parse_page_tree(self, response, parser_class):
1674        content = response.content
1675        content = content.decode(response.charset)
1676
1677        def _parse_html(html):
1678            parser = parser_class()
1679            parser.feed(html)
1680            parser.close()
1681            document = parser.root
1682            document.finalize()
1683            # Removing ROOT element if it's not necessary
1684            if len(document.children) == 1:
1685                if not isinstance(document.children[0], six.string_types):
1686                    document = document.children[0]
1687            return document
1688
1689        try:
1690            dom = _parse_html(content)
1691        except HTMLParseError as e:
1692            standardMsg = '%s\n%s' % ("Response's content is not valid HTML", e.msg)
1693            self.fail(self._formatMessage(None, standardMsg))
1694        return dom
1695
1696    def test_page_tree_regression_5892(self):
1697        # ref: https://github.com/divio/django-cms/issues/5892
1698        # Tests the escaping of characters for a german translation
1699        # in the page tree.
1700        superuser = self.get_superuser()
1701
1702        create_page('Home', 'nav_playground.html', 'en')
1703        alpha = create_page('Alpha', 'nav_playground.html', 'en')
1704        create_page('Beta', 'nav_playground.html', 'en', parent=alpha)
1705        create_page('Gamma', 'nav_playground.html', 'en')
1706
1707        with self.login_user_context(superuser):
1708            with force_language('de'):
1709                endpoint = self.get_admin_url(Page, 'get_tree')
1710                response = self.client.get(endpoint)
1711                self.assertEqual(response.status_code, 200)
1712                parsed = self._parse_page_tree(response, parser_class=PageTreeOptionsParser)
1713                content = force_text(parsed)
1714                self.assertIn(u'(Shift-Klick für erweiterte Einstellungen)', content)
1715
1716    def test_page_get_tree_endpoint_flat(self):
1717        superuser = self.get_superuser()
1718        endpoint = self.get_admin_url(Page, 'get_tree')
1719
1720        create_page('Home', 'nav_playground.html', 'en')
1721        alpha = create_page('Alpha', 'nav_playground.html', 'en')
1722        create_page('Beta', 'nav_playground.html', 'en', parent=alpha)
1723        create_page('Gamma', 'nav_playground.html', 'en')
1724
1725        tree = (
1726            '<li>\nHome\n</li>'
1727            '<li>\nAlpha\n</li>'
1728            '<li>\nGamma\n</li>'
1729        )
1730
1731        with self.login_user_context(superuser):
1732            response = self.client.get(endpoint)
1733            self.assertEqual(response.status_code, 200)
1734            parsed = self._parse_page_tree(response, parser_class=PageTreeLiParser)
1735            content = force_text(parsed)
1736            self.assertIn(tree, content)
1737            self.assertNotIn('<li>\nBeta\n</li>', content)
1738
1739    def test_page_get_tree_endpoint_nested(self):
1740        superuser = self.get_superuser()
1741        endpoint = self.get_admin_url(Page, 'get_tree')
1742
1743        create_page('Home', 'nav_playground.html', 'en')
1744        alpha = create_page('Alpha', 'nav_playground.html', 'en')
1745        create_page('Beta', 'nav_playground.html', 'en', parent=alpha)
1746        gamma = create_page('Gamma', 'nav_playground.html', 'en')
1747        create_page('Delta', 'nav_playground.html', 'en', parent=gamma)
1748        create_page('Theta', 'nav_playground.html', 'en')
1749
1750        tree = (
1751            '<li>\nHome\n</li>'
1752            '<li>\nAlpha'
1753            '<ul>\n<li>\nBeta\n</li>\n</ul>\n</li>'
1754            '<li>\nGamma'
1755            '<ul>\n<li>\nDelta\n</li>\n</ul>\n</li>'
1756            '<li>\nTheta\n</li>'
1757        )
1758
1759        data = {
1760            'openNodes[]': [alpha.node.pk, gamma.node.pk]
1761        }
1762
1763        with self.login_user_context(superuser):
1764            response = self.client.get(endpoint, data=data)
1765            self.assertEqual(response.status_code, 200)
1766            parsed = self._parse_page_tree(response, parser_class=PageTreeLiParser)
1767            content = force_text(parsed)
1768            self.assertIn(tree, content)
1769
1770    def test_page_changelist_search(self):
1771        superuser = self.get_superuser()
1772        endpoint = self.get_admin_url(Page, 'changelist')
1773
1774        create_page('Home', 'nav_playground.html', 'en')
1775        alpha = create_page('Alpha', 'nav_playground.html', 'en')
1776        create_page('Beta', 'nav_playground.html', 'en', parent=alpha)
1777        create_page('Gamma', 'nav_playground.html', 'en')
1778
1779        with self.login_user_context(superuser):
1780            response = self.client.get(endpoint, data={'q': 'alpha'})
1781            self.assertEqual(response.status_code, 200)
1782            parsed = self._parse_page_tree(response, parser_class=PageTreeLiParser)
1783            content = force_text(parsed)
1784            self.assertIn('<li>\nAlpha\n</li>', content)
1785            self.assertNotIn('<li>\nHome\n</li>', content)
1786            self.assertNotIn('<li>\nBeta\n</li>', content)
1787            self.assertNotIn('<li>\nGamma\n</li>', content)
1788
1789    def test_global_limit_on_plugin_move(self):
1790        superuser = self.get_superuser()
1791        cms_page = self.get_page()
1792        source_placeholder = cms_page.placeholders.get(slot='right-column')
1793        target_placeholder = cms_page.placeholders.get(slot='body')
1794        data = {
1795            'placeholder': source_placeholder,
1796            'plugin_type': 'LinkPlugin',
1797            'language': 'en',
1798        }
1799        plugin_1 = add_plugin(**data)
1800        plugin_2 = add_plugin(**data)
1801        plugin_3 = add_plugin(**data)
1802        with UserLoginContext(self, superuser):
1803            with self.settings(CMS_PLACEHOLDER_CONF=self.placeholderconf):
1804                data = {'placeholder_id': target_placeholder.pk, 'target_language': 'en', 'plugin_id': plugin_1.pk, 'plugin_parent': ''}
1805                endpoint = self.get_move_plugin_uri(plugin_1)
1806                response = self.client.post(endpoint, data) # first
1807                self.assertEqual(response.status_code, 200)
1808                data = {'placeholder_id': target_placeholder.pk, 'target_language': 'en', 'plugin_id': plugin_2.pk, 'plugin_parent': ''}
1809                endpoint = self.get_move_plugin_uri(plugin_2)
1810                response = self.client.post(endpoint, data) # second
1811                self.assertEqual(response.status_code, 200)
1812                data = {'placeholder_id': target_placeholder.pk, 'target_language': 'en', 'plugin_id': plugin_3.pk, 'plugin_parent': ''}
1813                endpoint = self.get_move_plugin_uri(plugin_3)
1814                response = self.client.post(endpoint, data) # third
1815                self.assertEqual(response.status_code, 400)
1816                self.assertEqual(response.content, b"This placeholder already has the maximum number of plugins (2).")
1817
1818    def test_type_limit_on_plugin_move(self):
1819        superuser = self.get_superuser()
1820        cms_page = self.get_page()
1821        source_placeholder = cms_page.placeholders.get(slot='right-column')
1822        target_placeholder = cms_page.placeholders.get(slot='body')
1823        data = {
1824            'placeholder': source_placeholder,
1825            'plugin_type': 'TextPlugin',
1826            'language': 'en',
1827        }
1828        plugin_1 = add_plugin(**data)
1829        plugin_2 = add_plugin(**data)
1830        with UserLoginContext(self, superuser):
1831            with self.settings(CMS_PLACEHOLDER_CONF=self.placeholderconf):
1832                data = {'placeholder_id': target_placeholder.pk, 'target_language': 'en', 'plugin_id': plugin_1.pk, 'plugin_parent': ''}
1833                endpoint = self.get_move_plugin_uri(plugin_1)
1834                response = self.client.post(endpoint, data) # first
1835                self.assertEqual(response.status_code, 200)
1836                data = {'placeholder_id': target_placeholder.pk, 'target_language': 'en', 'plugin_id': plugin_2.pk, 'plugin_parent': ''}
1837                endpoint = self.get_move_plugin_uri(plugin_1)
1838                response = self.client.post(endpoint, data) # second
1839                self.assertEqual(response.status_code, 400)
1840                self.assertEqual(response.content,
1841                                 b"This placeholder already has the maximum number (1) of allowed Text plugins.")
1842
1843    @override_settings(CMS_PLACEHOLDER_CACHE=True)
1844    def test_placeholder_cache_cleared_on_publish(self):
1845        page = self.get_page()
1846        staff_user = self.get_superuser()
1847        plugins = [
1848            self._add_plugin_to_page(page, 'TextPlugin', publish=False),
1849            self._add_plugin_to_page(page, 'LinkPlugin', publish=False),
1850        ]
1851
1852        with self.login_user_context(staff_user):
1853            # Publish the page
1854            publish_endpoint = self.get_admin_url(Page, 'publish_page', page.pk, 'en')
1855            self.client.post(publish_endpoint)
1856
1857        response = self.client.get(page.get_absolute_url())
1858        self.assertContains(response, '<p>text</p>', html=True)
1859        self.assertContains(response, '<a href="https://www.django-cms.org" >A Link</a>', html=True)
1860
1861        placeholder = plugins[0].placeholder
1862
1863        with self.login_user_context(staff_user):
1864            # Delete the plugins
1865            data = {'post': True}
1866
1867            for plugin in plugins:
1868                endpoint = self.get_delete_plugin_uri(plugin)
1869                response = self.client.post(endpoint, data)
1870                self.assertEqual(response.status_code, 302)
1871            self.assertEqual(placeholder.get_plugins('en').count(), 0)
1872
1873        with self.login_user_context(staff_user):
1874            # Publish the page
1875            publish_endpoint = self.get_admin_url(Page, 'publish_page', page.pk, 'en')
1876            self.client.post(publish_endpoint)
1877
1878        response = self.client.get(page.get_absolute_url())
1879        self.assertNotContains(response, '<p>text</p>', html=True)
1880        self.assertNotContains(response, '<a href="https://www.django-cms.org" >A Link</a>', html=True)
1881
1882    def test_clear_placeholder_marks_page_as_dirty(self):
1883        page = self.get_page()
1884        staff_user = self.get_superuser()
1885        plugins = [
1886            self._add_plugin_to_page(page, 'TextPlugin'),
1887            self._add_plugin_to_page(page, 'LinkPlugin'),
1888        ]
1889        placeholder = plugins[0].placeholder
1890        endpoint = self.get_clear_placeholder_url(placeholder)
1891
1892        with self.login_user_context(staff_user):
1893            self.assertEqual(page.reload().get_publisher_state("en"), PUBLISHER_STATE_DEFAULT)
1894            response = self.client.post(endpoint, {'test': ''})
1895            self.assertEqual(response.status_code, 302)
1896            self.assertEqual(placeholder.get_plugins('en').count(), 0)
1897            self.assertEqual(page.reload().get_publisher_state("en"), PUBLISHER_STATE_DIRTY)
1898
1899
1900class PermissionsTestCase(PageTestBase):
1901
1902    def _add_translation_to_page(self, page):
1903        translation = create_title(
1904            "de",
1905            "permissions-de",
1906            page.reload(),
1907            slug="permissions-de"
1908        )
1909        return translation
1910
1911    def _page_exists(self, reverse_id=None):
1912        if not reverse_id:
1913            reverse_id = 'permissions'
1914        return Page.objects.filter(reverse_id=reverse_id).exists()
1915
1916    def _page_permission_exists(self, **kwargs):
1917        return PagePermission.objects.filter(**kwargs).exists()
1918
1919    def _get_page_permissions_data(self, **kwargs):
1920        if 'id' in kwargs:
1921            initial = 1
1922        else:
1923            initial = 0
1924
1925        data = {
1926            'language': 'en',
1927            'limit_visibility_in_menu': '',
1928            'pagepermission_set-TOTAL_FORMS': 0,
1929            'pagepermission_set-INITIAL_FORMS': 0,
1930            'pagepermission_set-MAX_NUM_FORMS': 0,
1931            'pagepermission_set-2-TOTAL_FORMS': 1,
1932            'pagepermission_set-2-INITIAL_FORMS': initial,
1933            'pagepermission_set-2-MIN_NUM_FORMS': 0,
1934            'pagepermission_set-2-MAX_NUM_FORMS': 1000,
1935            'pagepermission_set-2-0-id': '',
1936            'pagepermission_set-2-0-page': '',
1937            'pagepermission_set-2-0-user': '',
1938            'pagepermission_set-2-0-group': '',
1939            'pagepermission_set-2-0-can_change': 'on',
1940            'pagepermission_set-2-0-can_change_permissions': 'on',
1941            'pagepermission_set-2-0-grant_on': 5,
1942        }
1943
1944        non_inline = ('language', 'limit_visibility_in_menu')
1945
1946        for attr, value in kwargs.items():
1947            if attr not in non_inline:
1948                attr = 'pagepermission_set-2-0-{}'.format(attr)
1949            data[attr] = value
1950        return data
1951
1952    def _get_page_view_restrictions_data(self, **kwargs):
1953        if 'id' in kwargs:
1954            initial = 1
1955        else:
1956            initial = 0
1957
1958        data = {
1959            'language': 'en',
1960            'limit_visibility_in_menu': '',
1961            'pagepermission_set-TOTAL_FORMS': 1,
1962            'pagepermission_set-INITIAL_FORMS': initial,
1963            'pagepermission_set-MIN_NUM_FORMS': 0,
1964            'pagepermission_set-MAX_NUM_FORMS': 1000,
1965            'pagepermission_set-0-id': '',
1966            'pagepermission_set-0-page': '',
1967            'pagepermission_set-0-user': '',
1968            'pagepermission_set-0-group': '',
1969            'pagepermission_set-0-can_view': 'on',
1970            'pagepermission_set-0-grant_on': 5,
1971            'pagepermission_set-2-TOTAL_FORMS': 0,
1972            'pagepermission_set-2-INITIAL_FORMS': 0,
1973            'pagepermission_set-2-MIN_NUM_FORMS': 0,
1974            'pagepermission_set-2-MAX_NUM_FORMS': 1000,
1975        }
1976
1977        non_inline = ('language', 'limit_visibility_in_menu')
1978
1979        for attr, value in kwargs.items():
1980            if attr not in non_inline:
1981                attr = 'pagepermission_set-0-{}'.format(attr)
1982            data[attr] = value
1983        return data
1984
1985
1986@override_settings(CMS_PERMISSION=True)
1987class PermissionsOnGlobalTest(PermissionsTestCase):
1988    """
1989    Tests all user interactions with the page admin
1990    while permissions are set to True and user has
1991    global permissions.
1992    """
1993
1994    def test_pages_in_admin_index(self):
1995        """
1996        User can see the "Pages" section the admin
1997        if he has change permissions on the Page model
1998        and he has global change permissions.
1999        """
2000        endpoint = admin_reverse('app_list', args=['cms'])
2001        staff_user = self.get_staff_user_with_no_permissions()
2002
2003        self.add_permission(staff_user, 'change_page')
2004        self.add_global_permission(staff_user, can_change=True)
2005
2006        with self.login_user_context(staff_user):
2007            response = self.client.get(endpoint)
2008            self.assertEqual(response.status_code, 200)
2009            self.assertContains(
2010                response,
2011                '<a href="/en/admin/cms/page/">Pages</a>',
2012                html=True,
2013            )
2014
2015        endpoint = self.get_admin_url(Page, 'changelist')
2016
2017        with self.login_user_context(staff_user):
2018            response = self.client.get(endpoint)
2019            self.assertEqual(response.status_code, 200)
2020
2021    def test_pages_not_in_admin_index(self):
2022        """
2023        User can't see the "Pages" section the admin
2024        if he does not have change permissions on the Page model
2025        and/or does not have global change permissions.
2026        """
2027        endpoint = admin_reverse('app_list', args=['cms'])
2028        staff_user = self.get_staff_user_with_no_permissions()
2029
2030        self.add_permission(staff_user, 'change_page')
2031        self.add_global_permission(staff_user, can_change=False)
2032
2033        with self.login_user_context(staff_user):
2034            response = self.client.get(endpoint)
2035            self.assertEqual(response.status_code, 404)
2036
2037        endpoint = self.get_admin_url(Page, 'changelist')
2038
2039        with self.login_user_context(staff_user):
2040            response = self.client.get(endpoint)
2041            self.assertEqual(response.status_code, 403)
2042
2043    def test_user_can_edit_page_settings(self):
2044        """
2045        User can edit page settings if he has change permissions
2046        on the Page model and and he has global change permissions.
2047        """
2048        page = self.get_permissions_test_page()
2049        endpoint = self.get_admin_url(Page, 'change', page.pk)
2050        redirect_to = self.get_admin_url(Page, 'changelist')
2051        staff_user = self.get_staff_user_with_no_permissions()
2052
2053        data = self._get_page_data(slug='permissions-2')
2054
2055        self.add_permission(staff_user, 'change_page')
2056        self.add_global_permission(staff_user, can_change=True)
2057
2058        with self.login_user_context(staff_user):
2059            response = self.client.post(endpoint, data)
2060            self.assertRedirects(response, redirect_to)
2061            self.assertTrue(self._translation_exists(slug='permissions-2'))
2062
2063    def test_user_cant_edit_page_settings(self):
2064        """
2065        User can't edit page settings if he does not
2066        have change permissions on the Page model and/or
2067        does not have global change permissions.
2068        """
2069        page = self.get_permissions_test_page()
2070        endpoint = self.get_admin_url(Page, 'change', page.pk)
2071        staff_user = self.get_staff_user_with_no_permissions()
2072
2073        data = self._get_page_data(slug='permissions-2')
2074
2075        self.add_permission(staff_user, 'change_page')
2076        gp = self.add_global_permission(staff_user, can_change=False)
2077
2078        with self.login_user_context(staff_user):
2079            response = self.client.post(endpoint, data)
2080            self.assertEqual(response.status_code, 403)
2081            self.assertFalse(self._translation_exists(slug='permissions-2'))
2082
2083        self.remove_permission(staff_user, 'change_page')
2084        gp.can_change = True
2085        gp.save(update_fields=['can_change'])
2086
2087        with self.login_user_context(staff_user):
2088            response = self.client.post(endpoint, data)
2089            self.assertEqual(response.status_code, 403)
2090            self.assertFalse(self._translation_exists(slug='permissions-2'))
2091
2092    def test_user_can_edit_advanced_page_settings(self):
2093        """
2094        User can edit advanced page settings if he has change permissions
2095        on the Page model, global change permissions and
2096        global change advanced settings permissions.
2097        """
2098        page = self.get_permissions_test_page()
2099        endpoint = self.get_admin_url(Page, 'advanced', page.pk)
2100        redirect_to = self.get_admin_url(Page, 'changelist')
2101        staff_user = self.get_staff_user_with_no_permissions()
2102
2103        data = self._get_page_data(reverse_id='permissions-2')
2104
2105        self.add_permission(staff_user, 'change_page')
2106        self.add_global_permission(
2107            staff_user,
2108            can_change=True,
2109            can_change_advanced_settings=True,
2110        )
2111
2112        with self.login_user_context(staff_user):
2113            response = self.client.post(endpoint, data)
2114            self.assertRedirects(response, redirect_to)
2115            self.assertTrue(self._page_exists(reverse_id='permissions-2'))
2116
2117    def test_user_cant_edit_advanced_page_settings(self):
2118        """
2119        User can't edit advanced page settings if he does not
2120        have change permissions on the Page model,
2121        does not have global change permissions and/or
2122        does not have global change advanced settings permissions.
2123        """
2124        page = self.get_permissions_test_page()
2125        endpoint = self.get_admin_url(Page, 'advanced', page.pk)
2126        staff_user = self.get_staff_user_with_no_permissions()
2127
2128        data = self._get_page_data(reverse_id='permissions-2')
2129
2130        self.add_permission(staff_user, 'change_page')
2131        gp = self.add_global_permission(
2132            staff_user,
2133            can_change=True,
2134            can_change_advanced_settings=False,
2135        )
2136
2137        with self.login_user_context(staff_user):
2138            response = self.client.post(endpoint, data)
2139            self.assertEqual(response.status_code, 403)
2140            self.assertFalse(self._page_exists(reverse_id='permissions-2'))
2141
2142        self.remove_permission(staff_user, 'change_page')
2143        gp.can_change = True
2144        gp.save(update_fields=['can_change'])
2145
2146        with self.login_user_context(staff_user):
2147            response = self.client.post(endpoint, data)
2148            self.assertEqual(response.status_code, 403)
2149            self.assertFalse(self._page_exists(reverse_id='permissions-2'))
2150
2151    def test_user_can_delete_empty_page(self):
2152        """
2153        User can delete an empty page if he has delete & change permissions
2154        on the Page model and he has global delete & change permissions.
2155        """
2156        page = self.get_permissions_test_page()
2157        endpoint = self.get_admin_url(Page, 'delete', page.pk)
2158        redirect_to = self.get_admin_url(Page, 'changelist')
2159        staff_user = self.get_staff_user_with_no_permissions()
2160
2161        self.add_permission(staff_user, 'change_page')
2162        self.add_permission(staff_user, 'delete_page')
2163        self.add_global_permission(staff_user, can_change=True, can_delete=True)
2164
2165        with self.login_user_context(staff_user):
2166            data = {'post': 'yes'}
2167            response = self.client.post(endpoint, data)
2168
2169            self.assertRedirects(response, redirect_to)
2170            self.assertFalse(self._page_exists())
2171
2172    def test_user_cant_delete_empty_page(self):
2173        """
2174        User can't delete an empty page if he does not
2175        have delete permissions on the Page model and/or
2176        does not have global delete permissions.
2177        """
2178        page = self.get_permissions_test_page()
2179        endpoint = self.get_admin_url(Page, 'delete', page.pk)
2180        staff_user = self.get_staff_user_with_no_permissions()
2181
2182        self.add_permission(staff_user, 'delete_page')
2183        gp = self.add_global_permission(staff_user, can_change=True, can_delete=False)
2184
2185        with self.login_user_context(staff_user):
2186            data = {'post': 'yes'}
2187
2188            response = self.client.post(endpoint, data)
2189            self.assertEqual(response.status_code, 403)
2190            self.assertTrue(self._page_exists())
2191
2192        self.remove_permission(staff_user, 'delete_page')
2193        gp.can_delete = True
2194        gp.save(update_fields=['can_delete'])
2195
2196        with self.login_user_context(staff_user):
2197            data = {'post': 'yes'}
2198
2199            response = self.client.post(endpoint, data)
2200            self.assertEqual(response.status_code, 403)
2201            self.assertTrue(self._page_exists())
2202
2203    def test_user_can_delete_non_empty_page(self):
2204        """
2205        User can delete a page with plugins if he has delete & change permissions
2206        on the Page model, delete permissions on the plugins in the page
2207        translations and global delete & change permissions.
2208        """
2209        page = self.get_permissions_test_page()
2210        endpoint = self.get_admin_url(Page, 'delete', page.pk)
2211        redirect_to = self.get_admin_url(Page, 'changelist')
2212        staff_user = self.get_staff_user_with_no_permissions()
2213
2214        self._add_plugin_to_page(page)
2215
2216        self.add_permission(staff_user, 'change_page')
2217        self.add_permission(staff_user, 'delete_page')
2218        self.add_permission(staff_user, 'delete_link')
2219        self.add_global_permission(staff_user, can_change=True, can_delete=True)
2220
2221        with self.login_user_context(staff_user):
2222            data = {'post': 'yes'}
2223            response = self.client.post(endpoint, data)
2224
2225            self.assertRedirects(response, redirect_to)
2226            self.assertFalse(self._page_exists())
2227
2228    def test_user_cant_delete_non_empty_page(self):
2229        """
2230        User can't delete a page with plugins if he
2231        does not have delete permissions on the Page model,
2232        does not have delete permissions on the plugins
2233        in the page translations, and/or does not have
2234        global delete permissions.
2235        """
2236        page = self.get_permissions_test_page()
2237        endpoint = self.get_admin_url(Page, 'delete', page.pk)
2238        staff_user = self.get_staff_user_with_no_permissions()
2239
2240        self._add_plugin_to_page(page)
2241
2242        self.add_permission(staff_user, 'change_page')
2243        self.add_permission(staff_user, 'delete_page')
2244        gp = self.add_global_permission(staff_user, can_change=True, can_delete=True)
2245
2246        with self.login_user_context(staff_user):
2247            data = {'post': 'yes'}
2248
2249            response = self.client.post(endpoint, data)
2250            self.assertEqual(response.status_code, 403)
2251            self.assertTrue(self._page_exists())
2252
2253        self.remove_permission(staff_user, 'delete_page')
2254        gp.can_delete = True
2255        gp.save(update_fields=['can_delete'])
2256
2257        with self.login_user_context(staff_user):
2258            data = {'post': 'yes'}
2259
2260            response = self.client.post(endpoint, data)
2261            self.assertEqual(response.status_code, 403)
2262            self.assertTrue(self._page_exists())
2263
2264    def test_user_can_delete_empty_translation(self):
2265        """
2266        User can delete an empty translation if he has
2267        delete & change permissions on the Page model and he has
2268        global delete & change permissions.
2269        """
2270        page = self.get_permissions_test_page()
2271        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
2272        redirect_to = self.get_admin_url(Page, 'changelist')
2273        staff_user = self.get_staff_user_with_no_permissions()
2274        translation = self._add_translation_to_page(page)
2275
2276        self.add_permission(staff_user, 'change_page')
2277        self.add_permission(staff_user, 'delete_page')
2278        self.add_global_permission(staff_user, can_change=True, can_delete=True)
2279
2280        with self.login_user_context(staff_user):
2281            data = {'language': translation.language}
2282            response = self.client.post(endpoint, data)
2283
2284            self.assertRedirects(response, redirect_to)
2285            self.assertFalse(self._translation_exists())
2286
2287    def test_user_cant_delete_empty_translation(self):
2288        """
2289        User can't delete an empty translation if he does not
2290        have delete permissions on the Page model and/or
2291        does not have global delete permissions.
2292        """
2293        page = self.get_permissions_test_page()
2294        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
2295        staff_user = self.get_staff_user_with_no_permissions()
2296        translation = self._add_translation_to_page(page)
2297
2298        self.add_permission(staff_user, 'change_page')
2299        self.add_permission(staff_user, 'delete_page')
2300        gp = self.add_global_permission(staff_user, can_change=True, can_delete=False)
2301
2302        with self.login_user_context(staff_user):
2303            data = {'language': translation.language}
2304
2305            response = self.client.post(endpoint, data)
2306            self.assertEqual(response.status_code, 403)
2307            self.assertTrue(self._translation_exists())
2308
2309        self.remove_permission(staff_user, 'delete_page')
2310        gp.can_delete = True
2311        gp.save(update_fields=['can_delete'])
2312
2313        with self.login_user_context(staff_user):
2314            data = {'language': translation.language}
2315
2316            response = self.client.post(endpoint, data)
2317            self.assertEqual(response.status_code, 403)
2318            self.assertTrue(self._translation_exists())
2319
2320    def test_user_can_delete_non_empty_translation(self):
2321        """
2322        User can delete a translation with plugins if he has delete & change permissions
2323        on the Page model, delete permissions on the plugins in the translation
2324        and global delete & change permissions.
2325        """
2326        page = self.get_permissions_test_page()
2327        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
2328        redirect_to = self.get_admin_url(Page, 'changelist')
2329        staff_user = self.get_staff_user_with_no_permissions()
2330        translation = self._add_translation_to_page(page)
2331
2332        self._add_plugin_to_page(page, language=translation.language)
2333
2334        self.add_permission(staff_user, 'change_page')
2335        self.add_permission(staff_user, 'delete_page')
2336        self.add_permission(staff_user, 'delete_link')
2337        self.add_global_permission(staff_user, can_change=True, can_delete=True)
2338
2339        with self.login_user_context(staff_user):
2340            data = {'language': translation.language}
2341            response = self.client.post(endpoint, data)
2342
2343            self.assertRedirects(response, redirect_to)
2344            self.assertFalse(self._translation_exists())
2345
2346    def test_user_cant_delete_non_empty_translation(self):
2347        """
2348        User can't delete a translation with plugins if he
2349        does not have delete permissions on the Page model,
2350        does not have delete permissions on the plugins in the translation,
2351        and/or does not have global delete permissions.
2352        """
2353        page = self.get_permissions_test_page()
2354        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
2355        staff_user = self.get_staff_user_with_no_permissions()
2356        translation = self._add_translation_to_page(page)
2357
2358        self._add_plugin_to_page(page, language=translation.language)
2359
2360        self.add_permission(staff_user, 'change_page')
2361        self.add_permission(staff_user, 'delete_page')
2362        self.add_global_permission(staff_user, can_change=True, can_delete=True)
2363
2364        with self.login_user_context(staff_user):
2365            data = {'language': translation.language}
2366
2367            response = self.client.post(endpoint, data)
2368            self.assertEqual(response.status_code, 403)
2369            self.assertTrue(self._translation_exists())
2370
2371    def test_user_can_change_template(self):
2372        """
2373        User can change a page's template if he
2374        has change permissions on the Page model and both
2375        global change and change advanced settings permissions.
2376        """
2377        page = self.get_permissions_test_page()
2378        staff_user = self.get_staff_user_with_no_permissions()
2379        endpoint = self.get_admin_url(Page, 'change_template', page.pk)
2380
2381        self.add_permission(staff_user, 'change_page')
2382        self.add_global_permission(staff_user, can_change=True, can_change_advanced_settings=True)
2383
2384        with self.login_user_context(staff_user):
2385            data = {'template': 'simple.html'}
2386            response = self.client.post(endpoint, data)
2387            self.assertContains(response, 'The template was successfully changed')
2388            page.refresh_from_db(fields=['template'])
2389            # clear the template cache
2390            page.__dict__.pop('_template_cache', None)
2391            self.assertEqual(page.get_template(), 'simple.html')
2392
2393    def test_user_cant_change_template(self):
2394        """
2395        User can't change a page's template if he
2396        does not have change permissions on the Page model,
2397        global change permissions and/or global change advanced settings
2398        permissions.
2399        """
2400        page = self.get_permissions_test_page()
2401        staff_user = self.get_staff_user_with_no_permissions()
2402        endpoint = self.get_admin_url(Page, 'change_template', page.pk)
2403
2404        self.add_permission(staff_user, 'change_page')
2405        self.add_global_permission(staff_user, can_change=True)
2406
2407        with self.login_user_context(staff_user):
2408            data = {'template': 'simple.html'}
2409            response = self.client.post(endpoint, data)
2410            self.assertEqual(response.status_code, 403)
2411            page.refresh_from_db(fields=['template'])
2412            self.assertEqual(page.get_template(), 'nav_playground.html')
2413
2414    def test_user_can_revert_non_empty_page_to_live(self):
2415        """
2416        User can revert a page to live with plugins if he has change permissions
2417        on the Page model, delete permissions on the plugins in the translation
2418        being reverted and page change permissions.
2419        """
2420        page = self.get_permissions_test_page()
2421        staff_user = self.get_staff_user_with_no_permissions()
2422        translation = self._add_translation_to_page(page)
2423        endpoint = self.get_admin_url(
2424            Page,
2425            'revert_to_live',
2426            page.pk,
2427            translation.language,
2428        )
2429        live_page = page.publisher_public
2430        draft_plugins = page.placeholders.get(slot='body').get_plugins(translation.language)
2431        live_plugins = live_page.placeholders.get(slot='body').get_plugins(translation.language)
2432
2433        self._add_plugin_to_page(page, language=translation.language)
2434
2435        page.publish(translation.language)
2436
2437        self._add_plugin_to_page(page, language=translation.language, publish=False)
2438
2439        self.add_permission(staff_user, 'change_page')
2440        self.add_permission(staff_user, 'delete_link')
2441        self.add_global_permission(staff_user, can_change=True)
2442
2443        with self.login_user_context(staff_user):
2444            self.assertEqual(draft_plugins.count(), 2)
2445            self.assertEqual(live_plugins.count(), 1)
2446
2447            data = {'language': translation.language}
2448
2449            self.client.post(endpoint, data)
2450            self.assertEqual(draft_plugins.count(), 1)
2451            self.assertEqual(live_plugins.count(), 1)
2452
2453    def test_user_cant_revert_non_empty_page_to_live(self):
2454        """
2455        User can't revert a page with plugins to live if he
2456        does not have has change permissions on the Page model,
2457        delete permissions on the plugins in the translation
2458        being reverted and/or does not have page change permissions.
2459        """
2460        page = self.get_permissions_test_page()
2461        staff_user = self.get_staff_user_with_no_permissions()
2462        translation = self._add_translation_to_page(page)
2463        endpoint = self.get_admin_url(
2464            Page,
2465            'revert_to_live',
2466            page.pk,
2467            translation.language,
2468        )
2469        live_page = page.publisher_public
2470        draft_plugins = page.placeholders.get(slot='body').get_plugins(translation.language)
2471        live_plugins = live_page.placeholders.get(slot='body').get_plugins(translation.language)
2472
2473        self._add_plugin_to_page(page, language=translation.language)
2474
2475        page.publish(translation.language)
2476
2477        self._add_plugin_to_page(page, language=translation.language, publish=False)
2478
2479        self.add_permission(staff_user, 'change_page')
2480        self.add_global_permission(staff_user, can_change=True)
2481
2482        with self.login_user_context(staff_user):
2483            self.assertEqual(draft_plugins.count(), 2)
2484            self.assertEqual(live_plugins.count(), 1)
2485
2486            data = {'language': translation.language}
2487            response = self.client.post(endpoint, data)
2488
2489            self.assertEqual(response.status_code, 403)
2490            self.assertEqual(draft_plugins.count(), 2)
2491            self.assertEqual(live_plugins.count(), 1)
2492
2493    def test_user_can_view_page_permissions_summary(self):
2494        """
2495        All staff users can see the permissions summary for a page.
2496        """
2497        page = self.get_permissions_test_page()
2498        endpoint = self.get_admin_url(Page, 'get_permissions', page.pk)
2499        staff_user = self.get_staff_user_with_no_permissions()
2500
2501        with self.login_user_context(staff_user):
2502            data = {'post': 'true'}
2503
2504            response = self.client.post(endpoint, data)
2505            self.assertEqual(response.status_code, 200)
2506            self.assertContains(
2507                response,
2508                "<p>Page doesn't inherit any permissions.</p>",
2509                html=True,
2510            )
2511
2512    def test_user_cant_view_page_permissions_summary(self):
2513        """
2514        Non staff users can't see the permissions summary for a page.
2515        """
2516        page = self.get_permissions_test_page()
2517        endpoint = self.get_admin_url(Page, 'get_permissions', page.pk)
2518        non_staff_user = self.get_standard_user()
2519
2520        with self.login_user_context(non_staff_user):
2521            data = {'post': 'true'}
2522
2523            response = self.client.post(endpoint, data)
2524            self.assertEqual(response.status_code, 302)
2525            self.assertRedirects(response, '/en/admin/login/?next=%s' % endpoint)
2526
2527    def test_user_can_add_page_permissions(self):
2528        """
2529        User can add page permissions if he has
2530        change permissions on the Page model,
2531        add permissions on the PagePermission model,
2532        global change permission and global change permissions permission.
2533        """
2534        admin = self.get_superuser()
2535        page = self.get_permissions_test_page()
2536        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2537        staff_user = self.get_staff_user_with_no_permissions()
2538        staff_user_2 = self.get_staff_page_user(created_by=admin)
2539
2540        data = self._get_page_permissions_data(
2541            page=page.pk,
2542            user=staff_user_2.pk,
2543        )
2544        data['_continue'] = '1'
2545
2546        self.add_permission(staff_user, 'change_page')
2547        self.add_permission(staff_user, 'add_pagepermission')
2548        self.add_global_permission(
2549            staff_user,
2550            can_change=True,
2551            can_change_permissions=True,
2552        )
2553
2554        with self.login_user_context(staff_user):
2555            response = self.client.post(endpoint, data)
2556            self.assertEqual(response.status_code, 302)
2557            self.assertRedirects(response, endpoint)
2558            self.assertTrue(self._page_permission_exists(user=staff_user_2))
2559
2560    def test_user_cant_add_page_permissions(self):
2561        """
2562        User can't add page permissions if he
2563        does not have change permissions on the Page model,
2564        does not have add permissions on the PagePermission model,
2565        does not have global change permission,
2566        and/or does not have global change permissions permission.
2567        """
2568        admin = self.get_superuser()
2569        page = self.get_permissions_test_page()
2570        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2571        staff_user = self.get_staff_user_with_no_permissions()
2572        staff_user_2 = self.get_staff_page_user(created_by=admin)
2573
2574        data = self._get_page_permissions_data(
2575            page=page.pk,
2576            user=staff_user_2.pk,
2577        )
2578        data['_continue'] = '1'
2579
2580        self.add_permission(staff_user, 'change_page')
2581        self.add_permission(staff_user, 'add_pagepermission')
2582        self.add_global_permission(
2583            staff_user,
2584            can_change=True,
2585            can_change_permissions=False,
2586        )
2587
2588        with self.login_user_context(staff_user):
2589            response = self.client.post(endpoint, data)
2590            self.assertEqual(response.status_code, 403)
2591            self.assertFalse(self._page_permission_exists(user=staff_user_2))
2592
2593    def test_user_can_edit_page_permissions(self):
2594        """
2595        User can edit page permissions if he has
2596        change permissions on the Page model,
2597        change permissions on the PagePermission model,
2598        global change permission and global change permissions permission.
2599        """
2600        admin = self.get_superuser()
2601        page = self.get_permissions_test_page()
2602        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2603        staff_user = self.get_staff_user_with_no_permissions()
2604        staff_user_2 = self.get_staff_page_user(created_by=admin)
2605
2606        permission = self.add_page_permission(
2607            user=staff_user_2,
2608            page=page,
2609            can_change_permissions=True
2610        )
2611
2612        data = self._get_page_permissions_data(
2613            page=page.pk,
2614            user=staff_user_2.pk,
2615            id=permission.pk,
2616            can_change_permissions=False,
2617        )
2618        data['_continue'] = '1'
2619
2620        self.add_permission(staff_user, 'change_page')
2621        self.add_permission(staff_user, 'change_pagepermission')
2622        self.add_global_permission(
2623            staff_user,
2624            can_change=True,
2625            can_change_permissions=True,
2626        )
2627
2628        with self.login_user_context(staff_user):
2629            response = self.client.post(endpoint, data)
2630            self.assertEqual(response.status_code, 302)
2631            self.assertRedirects(response, endpoint)
2632            self.assertTrue(
2633                self._page_permission_exists(
2634                    user=staff_user_2,
2635                    can_change_permissions=False,
2636                )
2637            )
2638
2639    def test_user_cant_edit_page_permissions(self):
2640        """
2641        User can't edit page permissions if he
2642        does not have change permissions on the Page model,
2643        does not have change permissions on the PagePermission model,
2644        does not have global change permission,
2645        and/or does not have global change permissions permission.
2646        """
2647        admin = self.get_superuser()
2648        page = self.get_permissions_test_page()
2649        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2650        staff_user = self.get_staff_user_with_no_permissions()
2651        staff_user_2 = self.get_staff_page_user(created_by=admin)
2652
2653        permission = self.add_page_permission(
2654            user=staff_user_2,
2655            page=page,
2656            can_change_permissions=True
2657        )
2658
2659        data = self._get_page_permissions_data(
2660            page=page.pk,
2661            user=staff_user_2.pk,
2662            id=permission.pk,
2663            can_change_permissions=False,
2664        )
2665        data['_continue'] = '1'
2666
2667        self.add_permission(staff_user, 'change_page')
2668        self.add_permission(staff_user, 'change_pagepermission')
2669        self.add_global_permission(
2670            staff_user,
2671            can_change=True,
2672            can_change_permissions=False,
2673        )
2674
2675        with self.login_user_context(staff_user):
2676            response = self.client.post(endpoint, data)
2677            self.assertEqual(response.status_code, 403)
2678            self.assertFalse(
2679                self._page_permission_exists(
2680                    user=staff_user_2,
2681                    can_change_permissions=False,
2682                )
2683            )
2684
2685    def test_user_can_delete_page_permissions(self):
2686        """
2687        User can delete page permissions if he has
2688        change permissions on the Page model,
2689        delete permissions on the PagePermission model,
2690        global change permission and global change permissions permission.
2691        """
2692        admin = self.get_superuser()
2693        page = self.get_permissions_test_page()
2694        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2695        staff_user = self.get_staff_user_with_no_permissions()
2696        staff_user_2 = self.get_staff_page_user(created_by=admin)
2697        permission = self.add_page_permission(user=staff_user_2, page=page)
2698
2699        data = self._get_page_permissions_data(
2700            page=page.pk,
2701            user=staff_user_2.pk,
2702            id=permission.pk,
2703            DELETE='on',
2704        )
2705        data['_continue'] = '1'
2706
2707        self.add_permission(staff_user, 'change_page')
2708        self.add_permission(staff_user, 'delete_pagepermission')
2709        self.add_global_permission(
2710            staff_user,
2711            can_change=True,
2712            can_change_permissions=True,
2713        )
2714
2715        with self.login_user_context(staff_user):
2716            response = self.client.post(endpoint, data)
2717            self.assertEqual(response.status_code, 302)
2718            self.assertRedirects(response, endpoint)
2719            self.assertFalse(self._page_permission_exists(user=staff_user_2))
2720
2721    def test_user_cant_delete_page_permissions(self):
2722        """
2723        User can't delete page permissions if he
2724        does not have change permissions on the Page model,
2725        does not have delete permissions on the PagePermission model,
2726        does not have global change permission,
2727        and/or does not have global change permissions permission.
2728        """
2729        admin = self.get_superuser()
2730        page = self.get_permissions_test_page()
2731        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2732        staff_user = self.get_staff_user_with_no_permissions()
2733        staff_user_2 = self.get_staff_page_user(created_by=admin)
2734        permission = self.add_page_permission(user=staff_user_2, page=page)
2735
2736        data = self._get_page_permissions_data(
2737            page=page.pk,
2738            user=staff_user_2.pk,
2739            id=permission.pk,
2740            DELETE='on',
2741        )
2742        data['_continue'] = '1'
2743
2744        self.add_permission(staff_user, 'change_page')
2745        self.add_permission(staff_user, 'delete_pagepermission')
2746        self.add_global_permission(
2747            staff_user,
2748            can_change=True,
2749            can_change_permissions=False,
2750        )
2751
2752        with self.login_user_context(staff_user):
2753            response = self.client.post(endpoint, data)
2754            self.assertEqual(response.status_code, 403)
2755            self.assertTrue(self._page_permission_exists(user=staff_user_2))
2756
2757    def test_user_can_add_page_view_restrictions(self):
2758        """
2759        User can add page view restrictions if he has
2760        change permissions on the Page model,
2761        add permissions on the PagePermission model,
2762        global change permission and global change permissions permission.
2763        """
2764        admin = self.get_superuser()
2765        page = self.get_permissions_test_page()
2766        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2767        staff_user = self.get_staff_user_with_no_permissions()
2768        staff_user_2 = self.get_staff_page_user(created_by=admin)
2769
2770        data = self._get_page_view_restrictions_data(
2771            page=page.pk,
2772            user=staff_user_2.pk,
2773        )
2774        data['_continue'] = '1'
2775
2776        self.add_permission(staff_user, 'change_page')
2777        self.add_permission(staff_user, 'add_pagepermission')
2778        self.add_global_permission(
2779            staff_user,
2780            can_change=True,
2781            can_change_permissions=True,
2782        )
2783
2784        with self.login_user_context(staff_user):
2785            response = self.client.post(endpoint, data)
2786            self.assertEqual(response.status_code, 302)
2787            self.assertRedirects(response, endpoint)
2788            self.assertTrue(self._page_permission_exists(user=staff_user_2, can_view=True))
2789
2790    def test_user_cant_add_page_view_restrictions(self):
2791        """
2792        User can't add page view restrictions if he
2793        does not have change permissions on the Page model,
2794        does not have add permissions on the PagePermission model,
2795        does not have global change permission,
2796        and/or does not have global change permissions permission.
2797        """
2798        admin = self.get_superuser()
2799        page = self.get_permissions_test_page()
2800        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2801        staff_user = self.get_staff_user_with_no_permissions()
2802        staff_user_2 = self.get_staff_page_user(created_by=admin)
2803
2804        data = self._get_page_view_restrictions_data(
2805            page=page.pk,
2806            user=staff_user_2.pk,
2807        )
2808        data['_continue'] = '1'
2809
2810        self.add_permission(staff_user, 'change_page')
2811        self.add_permission(staff_user, 'add_pagepermission')
2812        self.add_global_permission(
2813            staff_user,
2814            can_change=True,
2815            can_change_permissions=False,
2816        )
2817
2818        with self.login_user_context(staff_user):
2819            response = self.client.post(endpoint, data)
2820            self.assertEqual(response.status_code, 403)
2821            self.assertFalse(self._page_permission_exists(user=staff_user_2, can_view=True))
2822
2823    def test_user_can_edit_page_view_restrictions(self):
2824        """
2825        User can edit page view restrictions if he has
2826        change permissions on the Page model,
2827        change permissions on the PagePermission model,
2828        global change permission and global change permissions permission.
2829        """
2830        admin = self.get_superuser()
2831        page = self.get_permissions_test_page()
2832        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2833        staff_user = self.get_staff_user_with_no_permissions()
2834        staff_user_2 = self.get_staff_page_user(created_by=admin)
2835
2836        permission = self.add_page_permission(
2837            user=staff_user_2,
2838            page=page,
2839            can_view=True,
2840            grant_on=1,
2841        )
2842
2843        data = model_to_dict(permission, exclude=['group'])
2844        data['grant_on'] = 5
2845
2846        data = self._get_page_view_restrictions_data(**data)
2847        data['_continue'] = '1'
2848
2849        self.add_permission(staff_user, 'change_page')
2850        self.add_permission(staff_user, 'change_pagepermission')
2851        self.add_global_permission(
2852            staff_user,
2853            can_change=True,
2854            can_change_permissions=True,
2855        )
2856
2857        with self.login_user_context(staff_user):
2858            response = self.client.post(endpoint, data)
2859            self.assertEqual(response.status_code, 302)
2860            self.assertRedirects(response, endpoint)
2861            self.assertTrue(
2862                self._page_permission_exists(
2863                    user=staff_user_2,
2864                    grant_on=5,
2865                )
2866            )
2867
2868    def test_user_cant_edit_page_view_restrictions(self):
2869        """
2870        User can't edit page view restrictions if he
2871        does not have change permissions on the Page model,
2872        does not have change permissions on the PagePermission model,
2873        does not have global change permission,
2874        and/or does not have global change permissions permission.
2875        """
2876        admin = self.get_superuser()
2877        page = self.get_permissions_test_page()
2878        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2879        staff_user = self.get_staff_user_with_no_permissions()
2880        staff_user_2 = self.get_staff_page_user(created_by=admin)
2881        permission = self.add_page_permission(
2882            user=staff_user_2,
2883            page=page,
2884            can_view=True,
2885            grant_on=1,
2886        )
2887
2888        data = model_to_dict(permission, exclude=['group'])
2889        data['grant_on'] = 5
2890
2891        data = self._get_page_view_restrictions_data(**data)
2892        data['_continue'] = '1'
2893
2894        self.add_permission(staff_user, 'change_page')
2895        self.add_permission(staff_user, 'change_pagepermission')
2896        self.add_global_permission(
2897            staff_user,
2898            can_change=True,
2899            can_change_permissions=False,
2900        )
2901
2902        with self.login_user_context(staff_user):
2903            response = self.client.post(endpoint, data)
2904            self.assertEqual(response.status_code, 403)
2905            self.assertFalse(
2906                self._page_permission_exists(
2907                    user=staff_user_2,
2908                    grant_on=5,
2909                )
2910            )
2911
2912    def test_user_can_delete_page_view_restrictions(self):
2913        """
2914        User can delete view restrictions if he has
2915        change permissions on the Page model,
2916        delete permissions on the PagePermission model,
2917        global change permission and global change permissions permission.
2918        """
2919        admin = self.get_superuser()
2920        page = self.get_permissions_test_page()
2921        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2922        staff_user = self.get_staff_user_with_no_permissions()
2923        staff_user_2 = self.get_staff_page_user(created_by=admin)
2924        permission = self.add_page_permission(
2925            user=staff_user_2,
2926            page=page,
2927            can_view=True,
2928        )
2929
2930        data = model_to_dict(permission, exclude=['group'])
2931        data['DELETE'] = True
2932
2933        data = self._get_page_view_restrictions_data(**data)
2934        data['_continue'] = '1'
2935
2936        self.add_permission(staff_user, 'change_page')
2937        self.add_permission(staff_user, 'delete_pagepermission')
2938        self.add_global_permission(
2939            staff_user,
2940            can_change=True,
2941            can_change_permissions=True,
2942        )
2943
2944        with self.login_user_context(staff_user):
2945            response = self.client.post(endpoint, data)
2946            self.assertEqual(response.status_code, 302)
2947            self.assertRedirects(response, endpoint)
2948            self.assertFalse(self._page_permission_exists(user=staff_user_2, can_view=True))
2949
2950    def test_user_cant_delete_page_view_restrictions(self):
2951        """
2952        User can't delete view restrictions if he
2953        does not have change permissions on the Page model,
2954        does not have delete permissions on the PagePermission model,
2955        does not have global change permission,
2956        and/or does not have global change permissions permission.
2957        """
2958        admin = self.get_superuser()
2959        page = self.get_permissions_test_page()
2960        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2961        staff_user = self.get_staff_user_with_no_permissions()
2962        staff_user_2 = self.get_staff_page_user(created_by=admin)
2963        permission = self.add_page_permission(
2964            user=staff_user_2,
2965            page=page,
2966            can_view=True,
2967        )
2968
2969        data = model_to_dict(permission, exclude=['group'])
2970        data['DELETE'] = True
2971
2972        data = self._get_page_view_restrictions_data(**data)
2973        data['_continue'] = '1'
2974
2975        self.add_permission(staff_user, 'change_page')
2976        self.add_permission(staff_user, 'delete_pagepermission')
2977        self.add_global_permission(
2978            staff_user,
2979            can_change=True,
2980            can_change_permissions=False,
2981        )
2982
2983        with self.login_user_context(staff_user):
2984            response = self.client.post(endpoint, data)
2985            self.assertEqual(response.status_code, 403)
2986            self.assertTrue(self._page_permission_exists(user=staff_user_2, can_view=True))
2987
2988    def test_permissions_cache_invalidation(self):
2989        """
2990        Test permission cache clearing on page save
2991        """
2992        page = self.get_permissions_test_page()
2993        staff_user = self.get_staff_user_with_std_permissions()
2994        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
2995        set_permission_cache(staff_user, "change_page", [page.pk])
2996
2997        with self.login_user_context(self.get_superuser()):
2998            data = self._get_page_permissions_data(page=page.pk, user=staff_user.pk)
2999            data['_continue'] = '1'
3000            self.client.post(endpoint, data)
3001        self.assertIsNone(get_permission_cache(staff_user, "change_page"))
3002
3003    def test_user_can_edit_title_fields(self):
3004        """
3005        User can edit title (translation) fields if he has
3006        global change permissions.
3007        """
3008        page = self.get_permissions_test_page()
3009        staff_user = self.get_staff_user_with_no_permissions()
3010        title = self._add_translation_to_page(page)
3011        endpoint = self.get_admin_url(Page, 'edit_title_fields', page.pk, title.language)
3012
3013        self.add_permission(staff_user, 'change_page')
3014        self.add_global_permission(staff_user, can_change=True)
3015
3016        with self.login_user_context(staff_user):
3017            data = model_to_dict(title, fields=['title'])
3018            data['title'] = 'permissions-de-2'
3019
3020            response = self.client.post(endpoint, data)
3021            self.assertEqual(response.status_code, 200)
3022            self.assertTrue(self._translation_exists(title='permissions-de-2'))
3023
3024    def test_user_cant_edit_title_fields(self):
3025        """
3026        User can't edit title (translation) fields if he does not have
3027        global change permissions.
3028        """
3029        page = self.get_permissions_test_page()
3030        staff_user = self.get_staff_user_with_no_permissions()
3031        title = self._add_translation_to_page(page)
3032        endpoint = self.get_admin_url(Page, 'edit_title_fields', page.pk, title.language)
3033
3034        self.add_permission(staff_user, 'change_page')
3035        self.add_global_permission(staff_user, can_change=False)
3036
3037        with self.login_user_context(staff_user):
3038            data = model_to_dict(title, fields=['title'])
3039            data['title'] = 'permissions-de-2'
3040
3041            response = self.client.post(endpoint, data)
3042            self.assertEqual(response.status_code, 403)
3043            self.assertFalse(self._translation_exists(title='permissions-de-2'))
3044
3045    def test_user_can_copy_page(self):
3046        """
3047        Test that a page can be copied via the admin
3048        """
3049        page = self.get_permissions_test_page()
3050        staff_user = self.get_staff_user_with_no_permissions()
3051
3052        self.add_permission(staff_user, 'add_page')
3053        self.add_permission(staff_user, 'change_page')
3054        self.add_global_permission(
3055            staff_user,
3056            can_add=True,
3057            can_change=True,
3058        )
3059
3060        count = Page.objects.drafts().count()
3061
3062        with self.login_user_context(staff_user):
3063            endpoint = self.get_admin_url(Page, 'get_copy_dialog', page.pk)
3064            endpoint += '?source_site=%s' % page.node.site_id
3065            response = self.client.get(endpoint)
3066            self.assertEqual(response.status_code, 200)
3067
3068        with self.login_user_context(staff_user):
3069            self.copy_page(page, page, position=1)
3070        self.assertEqual(count + 1, 3)
3071
3072    # Plugin related tests
3073
3074    def test_user_can_add_plugin(self):
3075        """
3076        User can add a plugin if he has change permissions
3077        on the Page model, add permissions on the plugin model
3078        and global change permissions.
3079        """
3080        page = self.get_permissions_test_page()
3081        staff_user = self.get_staff_user_with_no_permissions()
3082        placeholder = page.placeholders.get(slot='body')
3083        plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin')
3084        endpoint = self._get_add_plugin_uri(page)
3085
3086        self.add_permission(staff_user, 'change_page')
3087        self.add_permission(staff_user, 'add_link')
3088        self.add_global_permission(staff_user, can_change=True)
3089
3090        with self.login_user_context(staff_user):
3091            data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}
3092            response = self.client.post(endpoint, data)
3093            self.assertEqual(response.status_code, 200)
3094            self.assertEqual(plugins.count(), 1)
3095
3096    def test_user_cant_add_plugin(self):
3097        """
3098        User can't add a plugin if he
3099        does not have change permissions on the Page model,
3100        does not have add permissions on the plugin model
3101        and/or does not have global change permissions.
3102        """
3103        page = self.get_permissions_test_page()
3104        staff_user = self.get_staff_user_with_no_permissions()
3105        placeholder = page.placeholders.get(slot='body')
3106        plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin')
3107        endpoint = self._get_add_plugin_uri(page)
3108
3109        self.add_permission(staff_user, 'change_page')
3110        self.add_permission(staff_user, 'add_link')
3111        self.add_global_permission(staff_user, can_change=False)
3112
3113        with self.login_user_context(staff_user):
3114            data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}
3115            response = self.client.post(endpoint, data)
3116            self.assertEqual(response.status_code, 403)
3117            self.assertEqual(plugins.count(), 0)
3118
3119    def test_user_can_edit_plugin(self):
3120        """
3121        User can edit a plugin if he has change permissions
3122        on the Page model, change permissions on the plugin model
3123        and global change permissions.
3124        """
3125        page = self.get_permissions_test_page()
3126        staff_user = self.get_staff_user_with_no_permissions()
3127        plugin = self._add_plugin_to_page(page)
3128        endpoint = self.get_change_plugin_uri(plugin)
3129
3130        self.add_permission(staff_user, 'change_page')
3131        self.add_permission(staff_user, 'change_link')
3132        self.add_global_permission(staff_user, can_change=True)
3133
3134        with self.login_user_context(staff_user):
3135            data = model_to_dict(plugin, fields=['name', 'external_link'])
3136            data['name'] = 'A link 2'
3137
3138            response = self.client.post(endpoint, data)
3139            self.assertEqual(response.status_code, 200)
3140            plugin.refresh_from_db()
3141            self.assertEqual(plugin.name, data['name'])
3142
3143    def test_user_cant_edit_plugin(self):
3144        """
3145        User can't edit a plugin if he
3146        does not have change permissions on the Page model,
3147        does not have change permissions on the plugin model
3148        and/or does not have global change permissions.
3149        """
3150        page = self.get_permissions_test_page()
3151        staff_user = self.get_staff_user_with_no_permissions()
3152        plugin = self._add_plugin_to_page(page)
3153        endpoint = self.get_change_plugin_uri(plugin)
3154
3155        self.add_permission(staff_user, 'change_page')
3156        self.add_permission(staff_user, 'change_link')
3157        self.add_global_permission(staff_user, can_change=False)
3158
3159        with self.login_user_context(staff_user):
3160            data = model_to_dict(plugin, fields=['name', 'external_link'])
3161            data['name'] = 'A link 2'
3162
3163            response = self.client.post(endpoint, data)
3164            self.assertEqual(response.status_code, 403)
3165            plugin.refresh_from_db()
3166            self.assertNotEqual(plugin.name, data['name'])
3167
3168    def test_user_can_delete_plugin(self):
3169        """
3170        User can delete a plugin if he has change permissions
3171        on the Page model, delete permissions on the plugin model
3172        and global change permissions.
3173        """
3174        page = self.get_permissions_test_page()
3175        staff_user = self.get_staff_user_with_no_permissions()
3176        plugin = self._add_plugin_to_page(page)
3177        endpoint = self.get_delete_plugin_uri(plugin)
3178
3179        self.add_permission(staff_user, 'change_page')
3180        self.add_permission(staff_user, 'delete_link')
3181        self.add_global_permission(staff_user, can_change=True)
3182
3183        with self.login_user_context(staff_user):
3184            data = {'post': True}
3185
3186            response = self.client.post(endpoint, data)
3187            self.assertEqual(response.status_code, 302)
3188            self.assertFalse(CMSPlugin.objects.filter(pk=plugin.pk).exists())
3189
3190    def test_user_cant_delete_plugin(self):
3191        """
3192        User can't delete a plugin if he
3193        does not have change permissions on the Page model,
3194        does not have delete permissions on the plugin model
3195        and/or does not have global change permissions.
3196        """
3197        page = self.get_permissions_test_page()
3198        staff_user = self.get_staff_user_with_no_permissions()
3199        plugin = self._add_plugin_to_page(page)
3200        endpoint = self.get_delete_plugin_uri(plugin)
3201
3202        self.add_permission(staff_user, 'change_page')
3203        self.add_permission(staff_user, 'delete_link')
3204        self.add_global_permission(staff_user, can_change=False)
3205
3206        with self.login_user_context(staff_user):
3207            data = {'post': True}
3208
3209            response = self.client.post(endpoint, data)
3210            self.assertEqual(response.status_code, 403)
3211            self.assertTrue(CMSPlugin.objects.filter(pk=plugin.pk).exists())
3212
3213    def test_user_can_move_plugin(self):
3214        """
3215        User can move a plugin if he has change permissions
3216        on the Page model, change permissions on the plugin model
3217        and global change permissions.
3218        """
3219        page = self.get_permissions_test_page()
3220        staff_user = self.get_staff_user_with_no_permissions()
3221        plugin = self._add_plugin_to_page(page)
3222        endpoint = self.get_move_plugin_uri(plugin)
3223        source_placeholder = plugin.placeholder
3224        target_placeholder = page.placeholders.get(slot='right-column')
3225
3226        data = {
3227            'plugin_id': plugin.pk,
3228            'target_language': 'en',
3229            'placeholder_id': target_placeholder.pk,
3230            'plugin_parent': '',
3231        }
3232
3233        self.add_permission(staff_user, 'change_page')
3234        self.add_permission(staff_user, 'change_link')
3235        self.add_global_permission(staff_user, can_change=True)
3236
3237        with self.login_user_context(staff_user):
3238            response = self.client.post(endpoint, data)
3239            self.assertEqual(response.status_code, 200)
3240            self.assertTrue(target_placeholder.get_plugins('en').filter(pk=plugin.pk))
3241            self.assertFalse(source_placeholder.get_plugins('en').filter(pk=plugin.pk))
3242
3243    def test_user_cant_move_plugin(self):
3244        """
3245        User can't move a plugin if he
3246        does not have change permissions on the Page model,
3247        does not have change permissions on the plugin model
3248        and/or does not have global change permissions.
3249        """
3250        page = self.get_permissions_test_page()
3251        staff_user = self.get_staff_user_with_no_permissions()
3252        plugin = self._add_plugin_to_page(page)
3253        endpoint = self.get_move_plugin_uri(plugin)
3254        source_placeholder = plugin.placeholder
3255        target_placeholder = page.placeholders.get(slot='right-column')
3256
3257        data = {
3258            'plugin_id': plugin.pk,
3259            'target_language': 'en',
3260            'placeholder_id': target_placeholder.pk,
3261            'plugin_parent': '',
3262        }
3263
3264        self.add_permission(staff_user, 'change_page')
3265        self.add_permission(staff_user, 'change_link')
3266        self.add_global_permission(staff_user, can_change=False)
3267
3268        with self.login_user_context(staff_user):
3269            response = self.client.post(endpoint, data)
3270            self.assertEqual(response.status_code, 403)
3271            self.assertFalse(target_placeholder.get_plugins('en').filter(pk=plugin.pk))
3272            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk))
3273
3274    def test_user_can_copy_plugin(self):
3275        """
3276        User can copy a plugin if he has change permissions
3277        on the Page model, add permissions on the plugin model
3278        and global change permissions.
3279        """
3280        page = self.get_permissions_test_page()
3281        staff_user = self.get_staff_user_with_no_permissions()
3282        plugin = self._add_plugin_to_page(page)
3283        translation = self._add_translation_to_page(page)
3284        endpoint = self.get_copy_plugin_uri(plugin)
3285        source_placeholder = plugin.placeholder
3286        target_placeholder = page.placeholders.get(slot='right-column')
3287
3288        data = {
3289            'source_plugin_id': plugin.pk,
3290            'source_placeholder_id': source_placeholder.pk,
3291            'source_language': plugin.language,
3292            'target_language': translation.language,
3293            'target_placeholder_id': target_placeholder.pk,
3294        }
3295
3296        self.add_permission(staff_user, 'change_page')
3297        self.add_permission(staff_user, 'add_link')
3298        self.add_global_permission(staff_user, can_change=True)
3299
3300        with self.login_user_context(staff_user):
3301            response = self.client.post(endpoint, data)
3302            self.assertEqual(response.status_code, 200)
3303            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists())
3304            self.assertTrue(
3305                target_placeholder
3306                .get_plugins(translation.language)
3307                .filter(plugin_type=plugin.plugin_type)
3308                .exists()
3309            )
3310
3311    def test_user_cant_copy_plugin(self):
3312        """
3313        User can't copy a plugin if he
3314        does not have change permissions on the Page model,
3315        does not have add permissions on the plugin model,
3316        and/or does not have global change permissions.
3317        """
3318        page = self.get_permissions_test_page()
3319        staff_user = self.get_staff_user_with_no_permissions()
3320        plugin = self._add_plugin_to_page(page)
3321        translation = self._add_translation_to_page(page)
3322        endpoint = self.get_copy_plugin_uri(plugin)
3323        source_placeholder = plugin.placeholder
3324        target_placeholder = page.placeholders.get(slot='right-column')
3325
3326        data = {
3327            'source_plugin_id': plugin.pk,
3328            'source_placeholder_id': source_placeholder.pk,
3329            'source_language': plugin.language,
3330            'target_language': translation.language,
3331            'target_placeholder_id': target_placeholder.pk,
3332        }
3333
3334        self.add_permission(staff_user, 'change_page')
3335        self.add_permission(staff_user, 'add_link')
3336        self.add_global_permission(staff_user, can_change=False)
3337
3338        with self.login_user_context(staff_user):
3339            response = self.client.post(endpoint, data)
3340            self.assertEqual(response.status_code, 403)
3341            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists())
3342            self.assertFalse(
3343                target_placeholder
3344                .get_plugins(translation.language)
3345                .filter(plugin_type=plugin.plugin_type)
3346                .exists()
3347            )
3348
3349    def test_user_can_copy_plugins_to_language(self):
3350        """
3351        User can copy all plugins to another language if he has
3352        change permissions on the Page model, add permissions on the
3353        plugins being copied and global change permissions.
3354        """
3355        page = self.get_permissions_test_page()
3356        staff_user = self.get_staff_user_with_no_permissions()
3357        translation = self._add_translation_to_page(page)
3358        endpoint = self.get_admin_url(Page, 'copy_language', page.pk)
3359        plugins = [
3360            self._add_plugin_to_page(page),
3361            self._add_plugin_to_page(page),
3362            self._add_plugin_to_page(page),
3363            self._add_plugin_to_page(page),
3364        ]
3365        placeholder = plugins[0].placeholder
3366
3367        data = {
3368            'source_language': 'en',
3369            'target_language': translation.language,
3370        }
3371
3372        self.add_permission(staff_user, 'change_page')
3373        self.add_permission(staff_user, 'add_link')
3374        self.add_global_permission(staff_user, can_change=True)
3375
3376        with self.login_user_context(staff_user):
3377            response = self.client.post(endpoint, data)
3378            self.assertEqual(response.status_code, 200)
3379            new_plugins = placeholder.get_plugins(translation.language)
3380            self.assertEqual(new_plugins.count(), len(plugins))
3381
3382    def test_user_cant_copy_plugins_to_language(self):
3383        """
3384        User can't copy all plugins to another language if he does have
3385        change permissions on the Page model, does not have add permissions
3386        on the plugins being copied and/or does not have global
3387        change permissions.
3388        """
3389        page = self.get_permissions_test_page()
3390        staff_user = self.get_staff_user_with_no_permissions()
3391        translation = self._add_translation_to_page(page)
3392        endpoint = self.get_admin_url(Page, 'copy_language', page.pk)
3393        plugins = [
3394            self._add_plugin_to_page(page),
3395            self._add_plugin_to_page(page),
3396            self._add_plugin_to_page(page),
3397            self._add_plugin_to_page(page),
3398        ]
3399        placeholder = plugins[0].placeholder
3400
3401        data = {
3402            'source_language': 'en',
3403            'target_language': translation.language,
3404        }
3405
3406        self.add_permission(staff_user, 'change_page')
3407        self.add_permission(staff_user, 'add_link')
3408        self.add_global_permission(staff_user, can_change=False)
3409
3410        with self.login_user_context(staff_user):
3411            response = self.client.post(endpoint, data)
3412            self.assertEqual(response.status_code, 403)
3413            new_plugins = placeholder.get_plugins(translation.language)
3414            self.assertEqual(new_plugins.count(), 0)
3415
3416    # Placeholder related tests
3417
3418    def test_user_can_clear_empty_placeholder(self):
3419        """
3420        User can clear an empty placeholder if he has change permissions
3421        on the Page model and global change permissions.
3422        """
3423        page = self.get_permissions_test_page()
3424
3425        staff_user = self.get_staff_user_with_no_permissions()
3426        placeholder = page.placeholders.get(slot='body')
3427        endpoint = self.get_clear_placeholder_url(placeholder)
3428
3429        self.add_permission(staff_user, 'change_page')
3430        self.add_global_permission(staff_user, can_change=True)
3431
3432        with self.login_user_context(staff_user):
3433            response = self.client.post(endpoint, {'test': 0})
3434            self.assertEqual(response.status_code, 302)
3435
3436    def test_user_cant_clear_empty_placeholder(self):
3437        """
3438        User can't clear an empty placeholder if he does not have
3439        change permissions on the Page model and/or does not have
3440        global change permissions.
3441        """
3442        page = self.get_permissions_test_page()
3443
3444        staff_user = self.get_staff_user_with_no_permissions()
3445        placeholder = page.placeholders.get(slot='body')
3446        endpoint = self.get_clear_placeholder_url(placeholder)
3447
3448        self.add_permission(staff_user, 'change_page')
3449        self.add_global_permission(staff_user, can_change=False)
3450
3451        with self.login_user_context(staff_user):
3452            response = self.client.post(endpoint, {'test': 0})
3453            self.assertEqual(response.status_code, 403)
3454
3455    def test_user_can_clear_non_empty_placeholder(self):
3456        """
3457        User can clear a placeholder with plugins if he has
3458        change permissions on the Page model, delete permissions
3459        on the plugin models in the placeholder and global change permissions.
3460        """
3461        page = self.get_permissions_test_page()
3462        staff_user = self.get_staff_user_with_no_permissions()
3463        plugins = [
3464            self._add_plugin_to_page(page, 'TextPlugin'),
3465            self._add_plugin_to_page(page, 'LinkPlugin'),
3466        ]
3467        placeholder = plugins[0].placeholder
3468        endpoint = self.get_clear_placeholder_url(placeholder)
3469
3470        self.add_permission(staff_user, 'delete_text')
3471        self.add_permission(staff_user, 'delete_link')
3472        self.add_permission(staff_user, 'change_page')
3473        self.add_global_permission(staff_user, can_change=True)
3474
3475        with self.login_user_context(staff_user):
3476            response = self.client.post(endpoint, {'test': 0})
3477            self.assertEqual(response.status_code, 302)
3478            self.assertEqual(placeholder.get_plugins('en').count(), 0)
3479
3480    def test_user_cant_clear_non_empty_placeholder(self):
3481        """
3482        User can't clear a placeholder with plugins if he does not have
3483        change permissions on the Page model, does not have delete
3484        permissions on the plugin models in the placeholder and/or
3485        does not have global change permissions.
3486        """
3487        page = self.get_permissions_test_page()
3488        staff_user = self.get_staff_user_with_no_permissions()
3489        plugins = [
3490            self._add_plugin_to_page(page, 'TextPlugin'),
3491            self._add_plugin_to_page(page, 'LinkPlugin'),
3492        ]
3493        placeholder = plugins[0].placeholder
3494        endpoint = self.get_clear_placeholder_url(placeholder)
3495
3496        self.add_permission(staff_user, 'delete_text')
3497        self.add_permission(staff_user, 'delete_link')
3498        self.add_permission(staff_user, 'change_page')
3499        self.add_global_permission(staff_user, can_change=False)
3500
3501        with self.login_user_context(staff_user):
3502            response = self.client.post(endpoint, {'test': 0})
3503            self.assertEqual(response.status_code, 403)
3504            self.assertEqual(placeholder.get_plugins('en').count(), 2)
3505
3506@override_settings(CMS_PERMISSION=True)
3507class PermissionsOnPageTest(PermissionsTestCase):
3508    """
3509    Tests all user interactions with the page admin
3510    while permissions are set to True and user has
3511    page permissions.
3512    """
3513
3514    def setUp(self):
3515        self._permissions_page = self.get_permissions_test_page()
3516
3517    def test_pages_in_admin_index(self):
3518        """
3519        User can see the "Pages" section the admin
3520        if he has change permissions on the Page model
3521        and he has global change permissions.
3522        """
3523        page = self._permissions_page
3524        endpoint = admin_reverse('app_list', args=['cms'])
3525        staff_user = self.get_staff_user_with_no_permissions()
3526
3527        self.add_permission(staff_user, 'change_page')
3528        self.add_page_permission(
3529            staff_user,
3530            page,
3531            can_change=True,
3532        )
3533
3534        with self.login_user_context(staff_user):
3535            response = self.client.get(endpoint)
3536            self.assertEqual(response.status_code, 200)
3537            self.assertContains(
3538                response,
3539                '<a href="/en/admin/cms/page/">Pages</a>',
3540                html=True,
3541            )
3542
3543        endpoint = self.get_admin_url(Page, 'changelist')
3544
3545        with self.login_user_context(staff_user):
3546            response = self.client.get(endpoint)
3547            self.assertEqual(response.status_code, 200)
3548
3549    def test_pages_not_in_admin_index(self):
3550        """
3551        User can't see the "Pages" section the admin
3552        if he does not have change permissions on the Page model
3553        and/or does not have global change permissions.
3554        """
3555        page = self._permissions_page
3556        endpoint = admin_reverse('app_list', args=['cms'])
3557        staff_user = self.get_staff_user_with_no_permissions()
3558
3559        self.add_permission(staff_user, 'change_page')
3560        self.add_page_permission(
3561            staff_user,
3562            page,
3563            can_change=False,
3564        )
3565
3566        with self.login_user_context(staff_user):
3567            response = self.client.get(endpoint)
3568            self.assertEqual(response.status_code, 404)
3569
3570        endpoint = self.get_admin_url(Page, 'changelist')
3571
3572        with self.login_user_context(staff_user):
3573            response = self.client.get(endpoint)
3574            self.assertEqual(response.status_code, 403)
3575
3576    def test_user_can_edit_page_settings(self):
3577        """
3578        User can edit page settings if he has change permissions
3579        on the Page model and and he has global change permissions.
3580        """
3581        page = self._permissions_page
3582        endpoint = self.get_admin_url(Page, 'change', page.pk)
3583        redirect_to = self.get_admin_url(Page, 'changelist')
3584        staff_user = self.get_staff_user_with_no_permissions()
3585
3586        data = self._get_page_data(slug='permissions-2')
3587
3588        self.add_permission(staff_user, 'change_page')
3589        self.add_page_permission(
3590            staff_user,
3591            page,
3592            can_change=True,
3593        )
3594
3595        with self.login_user_context(staff_user):
3596            response = self.client.post(endpoint, data)
3597            self.assertRedirects(response, redirect_to)
3598            self.assertTrue(self._translation_exists(slug='permissions-2'))
3599
3600    def test_user_cant_edit_page_settings(self):
3601        """
3602        User can't edit page settings if he does not
3603        have change permissions on the Page model and/or
3604        does not have global change permissions.
3605        """
3606        page = self._permissions_page
3607        endpoint = self.get_admin_url(Page, 'change', page.pk)
3608        staff_user = self.get_staff_user_with_no_permissions()
3609
3610        data = self._get_page_data(slug='permissions-2')
3611
3612        self.add_permission(staff_user, 'change_page')
3613        page_perm = self.add_page_permission(
3614            staff_user,
3615            page,
3616            can_change=False,
3617        )
3618
3619        with self.login_user_context(staff_user):
3620            response = self.client.post(endpoint, data)
3621            self.assertEqual(response.status_code, 403)
3622            self.assertFalse(self._translation_exists(slug='permissions-2'))
3623
3624        self.remove_permission(staff_user, 'change_page')
3625        page_perm.can_change = True
3626        page_perm.save(update_fields=['can_change'])
3627
3628        with self.login_user_context(staff_user):
3629            response = self.client.post(endpoint, data)
3630            self.assertEqual(response.status_code, 403)
3631            self.assertFalse(self._translation_exists(slug='permissions-2'))
3632
3633    def test_user_can_edit_advanced_page_settings(self):
3634        """
3635        User can edit advanced page settings if he has change permissions
3636        on the Page model, global change permissions and
3637        global change advanced settings permissions.
3638        """
3639        page = self._permissions_page
3640        endpoint = self.get_admin_url(Page, 'advanced', page.pk)
3641        redirect_to = self.get_admin_url(Page, 'changelist')
3642        staff_user = self.get_staff_user_with_no_permissions()
3643
3644        data = self._get_page_data(reverse_id='permissions-2')
3645
3646        self.add_permission(staff_user, 'change_page')
3647        self.add_page_permission(
3648            staff_user,
3649            page,
3650            can_change=True,
3651            can_change_advanced_settings=True,
3652        )
3653
3654        with self.login_user_context(staff_user):
3655            response = self.client.post(endpoint, data)
3656            self.assertRedirects(response, redirect_to)
3657            self.assertTrue(self._page_exists(reverse_id='permissions-2'))
3658
3659    def test_user_cant_edit_advanced_page_settings(self):
3660        """
3661        User can't edit advanced page settings if he does not
3662        have change permissions on the Page model,
3663        does not have global change permissions and/or
3664        does not have global change advanced settings permissions.
3665        """
3666        page = self._permissions_page
3667        endpoint = self.get_admin_url(Page, 'advanced', page.pk)
3668        staff_user = self.get_staff_user_with_no_permissions()
3669
3670        data = self._get_page_data(reverse_id='permissions-2')
3671
3672        self.add_permission(staff_user, 'change_page')
3673        page_perm = self.add_page_permission(
3674            staff_user,
3675            page,
3676            can_change=True,
3677            can_change_advanced_settings=False,
3678        )
3679
3680        with self.login_user_context(staff_user):
3681            response = self.client.post(endpoint, data)
3682            self.assertEqual(response.status_code, 403)
3683            self.assertFalse(self._page_exists(reverse_id='permissions-2'))
3684
3685        self.remove_permission(staff_user, 'change_page')
3686        page_perm.can_change = True
3687        page_perm.save(update_fields=['can_change'])
3688
3689        with self.login_user_context(staff_user):
3690            response = self.client.post(endpoint, data)
3691            self.assertEqual(response.status_code, 403)
3692            self.assertFalse(self._page_exists(reverse_id='permissions-2'))
3693
3694    def test_user_can_delete_empty_page(self):
3695        """
3696        User can delete an empty page if he has delete & change permissions
3697        on the Page model and he has page delete & change permissions.
3698        """
3699        page = self._permissions_page
3700        endpoint = self.get_admin_url(Page, 'delete', page.pk)
3701        redirect_to = admin_reverse('index')
3702        staff_user = self.get_staff_user_with_no_permissions()
3703
3704        self.add_permission(staff_user, 'change_page')
3705        self.add_permission(staff_user, 'delete_page')
3706        self.add_page_permission(
3707            staff_user,
3708            page,
3709            can_change=True,
3710            can_delete=True,
3711        )
3712
3713        with self.login_user_context(staff_user):
3714            data = {'post': 'yes'}
3715            response = self.client.post(endpoint, data)
3716
3717            self.assertRedirects(response, redirect_to)
3718            self.assertFalse(self._page_exists())
3719
3720    def test_user_cant_delete_empty_page(self):
3721        """
3722        User can't delete an empty page if he does not
3723        have delete permissions on the Page model and/or
3724        does not have global delete permissions.
3725        """
3726        page = self._permissions_page
3727        endpoint = self.get_admin_url(Page, 'delete', page.pk)
3728        staff_user = self.get_staff_user_with_no_permissions()
3729
3730        self.add_permission(staff_user, 'change_page')
3731        self.add_permission(staff_user, 'delete_page')
3732        page_perm = self.add_page_permission(
3733            staff_user,
3734            page,
3735            can_change=False,
3736            can_delete=False,
3737        )
3738
3739        with self.login_user_context(staff_user):
3740            data = {'post': 'yes'}
3741
3742            response = self.client.post(endpoint, data)
3743            self.assertEqual(response.status_code, 403)
3744            self.assertTrue(self._page_exists())
3745
3746        self.remove_permission(staff_user, 'delete_page')
3747        page_perm.can_delete = True
3748        page_perm.save(update_fields=['can_delete'])
3749
3750        with self.login_user_context(staff_user):
3751            data = {'post': 'yes'}
3752
3753            response = self.client.post(endpoint, data)
3754            self.assertEqual(response.status_code, 403)
3755            self.assertTrue(self._page_exists())
3756
3757    def test_user_can_delete_non_empty_page(self):
3758        """
3759        User can delete a page with plugins if he has delete permissions
3760        on the Page model, delete permissions on the plugins in the page
3761        translations and page delete & change permissions.
3762        """
3763        page = self._permissions_page
3764        endpoint = self.get_admin_url(Page, 'delete', page.pk)
3765        redirect_to = admin_reverse('index')
3766        staff_user = self.get_staff_user_with_no_permissions()
3767
3768        self._add_plugin_to_page(page)
3769
3770        self.add_permission(staff_user, 'change_page')
3771        self.add_permission(staff_user, 'delete_page')
3772        self.add_permission(staff_user, 'delete_link')
3773        self.add_page_permission(
3774            staff_user,
3775            page,
3776            can_change=True,
3777            can_delete=True,
3778        )
3779
3780        with self.login_user_context(staff_user):
3781            data = {'post': 'yes'}
3782            response = self.client.post(endpoint, data)
3783
3784            self.assertRedirects(response, redirect_to)
3785            self.assertFalse(self._page_exists())
3786
3787    def test_user_cant_delete_non_empty_page(self):
3788        """
3789        User can't delete a page with plugins if he
3790        does not have delete permissions on the Page model,
3791        does not have delete permissions on the plugins
3792        in the page translations, and/or does not have
3793        global delete permissions.
3794        """
3795        page = self._permissions_page
3796        endpoint = self.get_admin_url(Page, 'delete', page.pk)
3797        staff_user = self.get_staff_user_with_no_permissions()
3798
3799        self._add_plugin_to_page(page)
3800        self.add_permission(staff_user, 'change_page')
3801        self.add_permission(staff_user, 'delete_page')
3802
3803        page_perm = self.add_page_permission(
3804            staff_user,
3805            page,
3806            can_change=True,
3807            can_delete=True,
3808        )
3809
3810        with self.login_user_context(staff_user):
3811            data = {'post': 'yes'}
3812
3813            response = self.client.post(endpoint, data)
3814            self.assertEqual(response.status_code, 403)
3815            self.assertTrue(self._page_exists())
3816
3817        self.remove_permission(staff_user, 'delete_page')
3818        page_perm.can_delete = True
3819        page_perm.save(update_fields=['can_delete'])
3820
3821        with self.login_user_context(staff_user):
3822            data = {'post': 'yes'}
3823
3824            response = self.client.post(endpoint, data)
3825            self.assertEqual(response.status_code, 403)
3826            self.assertTrue(self._page_exists())
3827
3828    def test_user_can_delete_empty_translation(self):
3829        """
3830        User can delete an empty translation if he has
3831        delete permissions on the Page model and he has
3832        page delete & change permissions.
3833        """
3834        page = self._permissions_page
3835        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
3836        redirect_to = self.get_admin_url(Page, 'changelist')
3837        staff_user = self.get_staff_user_with_no_permissions()
3838        translation = self._add_translation_to_page(page)
3839
3840        self.add_permission(staff_user, 'change_page')
3841        self.add_permission(staff_user, 'delete_page')
3842        self.add_page_permission(
3843            staff_user,
3844            page,
3845            can_change=True,
3846            can_delete=True,
3847        )
3848
3849        with self.login_user_context(staff_user):
3850            data = {'language': translation.language}
3851            response = self.client.post(endpoint, data)
3852
3853            self.assertRedirects(response, redirect_to)
3854            self.assertFalse(self._translation_exists())
3855
3856    def test_user_cant_delete_empty_translation(self):
3857        """
3858        User can't delete an empty translation if he does not
3859        have delete permissions on the Page model and/or
3860        does not have global delete permissions.
3861        """
3862        page = self._permissions_page
3863        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
3864        staff_user = self.get_staff_user_with_no_permissions()
3865        translation = self._add_translation_to_page(page)
3866
3867        self.add_permission(staff_user, 'change_page')
3868        self.add_permission(staff_user, 'delete_page')
3869        page_perm = self.add_page_permission(
3870            staff_user,
3871            page,
3872            can_change=False,
3873            can_delete=False,
3874        )
3875
3876        with self.login_user_context(staff_user):
3877            data = {'language': translation.language}
3878
3879            response = self.client.post(endpoint, data)
3880            self.assertEqual(response.status_code, 403)
3881            self.assertTrue(self._translation_exists())
3882
3883        self.remove_permission(staff_user, 'delete_page')
3884        page_perm.can_delete = True
3885        page_perm.save(update_fields=['can_delete'])
3886
3887        with self.login_user_context(staff_user):
3888            data = {'language': translation.language}
3889
3890            response = self.client.post(endpoint, data)
3891            self.assertEqual(response.status_code, 403)
3892            self.assertTrue(self._translation_exists())
3893
3894    def test_user_can_delete_non_empty_translation(self):
3895        """
3896        User can delete a translation with plugins if he has delete permissions
3897        on the Page model, delete permissions on the plugins in the translation
3898        and page delete & change permissions.
3899        """
3900        page = self._permissions_page
3901        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
3902        redirect_to = self.get_admin_url(Page, 'changelist')
3903        staff_user = self.get_staff_user_with_no_permissions()
3904        translation = self._add_translation_to_page(page)
3905
3906        self._add_plugin_to_page(page, language=translation.language)
3907
3908        self.add_permission(staff_user, 'change_page')
3909        self.add_permission(staff_user, 'delete_page')
3910        self.add_permission(staff_user, 'delete_link')
3911        self.add_page_permission(
3912            staff_user,
3913            page,
3914            can_change=True,
3915            can_delete=True,
3916        )
3917
3918        with self.login_user_context(staff_user):
3919            data = {'language': translation.language}
3920            response = self.client.post(endpoint, data)
3921
3922            self.assertRedirects(response, redirect_to)
3923            self.assertFalse(self._translation_exists())
3924
3925    def test_user_cant_delete_non_empty_translation(self):
3926        """
3927        User can't delete a translation with plugins if he
3928        does not have delete permissions on the Page model,
3929        does not have delete permissions on the plugins in the translation,
3930        and/or does not have global delete permissions.
3931        """
3932        page = self._permissions_page
3933        endpoint = self.get_admin_url(Page, 'delete_translation', page.pk)
3934        staff_user = self.get_staff_user_with_no_permissions()
3935        translation = self._add_translation_to_page(page)
3936
3937        self._add_plugin_to_page(page, language=translation.language)
3938
3939        self.add_permission(staff_user, 'change_page')
3940        self.add_permission(staff_user, 'delete_page')
3941        self.add_page_permission(
3942            staff_user,
3943            page,
3944            can_change=True,
3945            can_delete=True,
3946        )
3947
3948        with self.login_user_context(staff_user):
3949            data = {'language': translation.language}
3950
3951            response = self.client.post(endpoint, data)
3952            self.assertEqual(response.status_code, 403)
3953            self.assertTrue(self._translation_exists())
3954
3955    def test_user_can_revert_non_empty_page_to_live(self):
3956        """
3957        User can revert a page to live with plugins if he has change permissions
3958        on the Page model, delete permissions on the plugins in the translation
3959        being reverted and page change permissions.
3960        """
3961        page = self._permissions_page
3962        staff_user = self.get_staff_user_with_no_permissions()
3963        translation = self._add_translation_to_page(page)
3964        endpoint = self.get_admin_url(
3965            Page,
3966            'revert_to_live',
3967            page.pk,
3968            translation.language,
3969        )
3970        live_page = page.publisher_public
3971        draft_plugins = page.placeholders.get(slot='body').get_plugins(translation.language)
3972        live_plugins = live_page.placeholders.get(slot='body').get_plugins(translation.language)
3973
3974        self._add_plugin_to_page(page, language=translation.language)
3975
3976        page.publish(translation.language)
3977
3978        self._add_plugin_to_page(page, language=translation.language, publish=False)
3979
3980        self.add_permission(staff_user, 'change_page')
3981        self.add_permission(staff_user, 'delete_link')
3982        self.add_page_permission(
3983            staff_user,
3984            page,
3985            can_change=True,
3986        )
3987
3988        with self.login_user_context(staff_user):
3989            self.assertEqual(draft_plugins.count(), 2)
3990            self.assertEqual(live_plugins.count(), 1)
3991
3992            data = {'language': translation.language}
3993
3994            self.client.post(endpoint, data)
3995            self.assertEqual(draft_plugins.count(), 1)
3996            self.assertEqual(live_plugins.count(), 1)
3997
3998    def test_user_cant_revert_non_empty_page_to_live(self):
3999        """
4000        User can't revert a page with plugins to live if he
4001        does not have has change permissions on the Page model,
4002        delete permissions on the plugins in the translation
4003        being reverted and/or does not have page change permissions.
4004        """
4005        page = self._permissions_page
4006        staff_user = self.get_staff_user_with_no_permissions()
4007        translation = self._add_translation_to_page(page)
4008        endpoint = self.get_admin_url(
4009            Page,
4010            'revert_to_live',
4011            page.pk,
4012            translation.language,
4013        )
4014        live_page = page.publisher_public
4015        draft_plugins = page.placeholders.get(slot='body').get_plugins(translation.language)
4016        live_plugins = live_page.placeholders.get(slot='body').get_plugins(translation.language)
4017
4018        self._add_plugin_to_page(page, language=translation.language)
4019
4020        page.publish(translation.language)
4021
4022        self._add_plugin_to_page(page, language=translation.language, publish=False)
4023
4024        self.add_permission(staff_user, 'change_page')
4025        self.add_page_permission(
4026            staff_user,
4027            page,
4028            can_change=True,
4029        )
4030
4031        with self.login_user_context(staff_user):
4032            self.assertEqual(draft_plugins.count(), 2)
4033            self.assertEqual(live_plugins.count(), 1)
4034
4035            data = {'language': translation.language}
4036            response = self.client.post(endpoint, data)
4037
4038            self.assertEqual(response.status_code, 403)
4039            self.assertEqual(draft_plugins.count(), 2)
4040            self.assertEqual(live_plugins.count(), 1)
4041
4042    def test_user_can_add_page_permissions(self):
4043        """
4044        User can add page permissions if he has
4045        change permissions on the Page model,
4046        add permissions on the PagePermission model,
4047        global change permission and global change permissions permission.
4048        """
4049        page = self._permissions_page
4050        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4051        staff_user = self.get_staff_user_with_no_permissions()
4052        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4053
4054        data = self._get_page_permissions_data(
4055            page=page.pk,
4056            user=staff_user_2.pk,
4057        )
4058        data['_continue'] = '1'
4059
4060        self.add_permission(staff_user, 'change_page')
4061        self.add_permission(staff_user, 'add_pagepermission')
4062        self.add_page_permission(
4063            staff_user,
4064            page,
4065            can_change=True,
4066            can_change_permissions=True,
4067        )
4068
4069        with self.login_user_context(staff_user):
4070            response = self.client.post(endpoint, data)
4071            self.assertEqual(response.status_code, 302)
4072            self.assertRedirects(response, endpoint)
4073            self.assertTrue(self._page_permission_exists(user=staff_user_2))
4074
4075    def test_user_cant_add_page_permissions(self):
4076        """
4077        User can't add page permissions if he
4078        does not have change permissions on the Page model,
4079        does not have add permissions on the PagePermission model,
4080        does not have global change permission,
4081        and/or does not have global change permissions permission.
4082        """
4083        page = self._permissions_page
4084        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4085        staff_user = self.get_staff_user_with_no_permissions()
4086        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4087
4088        data = self._get_page_permissions_data(
4089            page=page.pk,
4090            user=staff_user_2.pk,
4091        )
4092        data['_continue'] = '1'
4093
4094        self.add_permission(staff_user, 'change_page')
4095        self.add_permission(staff_user, 'add_pagepermission')
4096        self.add_page_permission(
4097            staff_user,
4098            page,
4099            can_change=True,
4100            can_change_permissions=False,
4101        )
4102
4103        with self.login_user_context(staff_user):
4104            response = self.client.post(endpoint, data)
4105            self.assertEqual(response.status_code, 403)
4106            self.assertFalse(self._page_permission_exists(user=staff_user_2))
4107
4108    def test_user_can_edit_page_permissions(self):
4109        """
4110        User can edit page permissions if he has
4111        change permissions on the Page model,
4112        change permissions on the PagePermission model,
4113        global change permission and global change permissions permission.
4114        """
4115        page = self._permissions_page
4116        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4117        staff_user = self.get_staff_user_with_no_permissions()
4118        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4119
4120        permission = self.add_page_permission(
4121            user=staff_user_2,
4122            page=page,
4123            can_change_permissions=True
4124        )
4125
4126        data = self._get_page_permissions_data(
4127            page=page.pk,
4128            user=staff_user_2.pk,
4129            id=permission.pk,
4130            can_change_permissions=False,
4131        )
4132        data['_continue'] = '1'
4133
4134        self.add_permission(staff_user, 'change_page')
4135        self.add_permission(staff_user, 'change_pagepermission')
4136        self.add_page_permission(
4137            staff_user,
4138            page,
4139            can_change=True,
4140            can_change_permissions=True,
4141        )
4142
4143        with self.login_user_context(staff_user):
4144            response = self.client.post(endpoint, data)
4145            self.assertEqual(response.status_code, 302)
4146            self.assertRedirects(response, endpoint)
4147            self.assertTrue(
4148                self._page_permission_exists(
4149                    user=staff_user_2,
4150                    can_change_permissions=False,
4151                )
4152            )
4153
4154    def test_user_cant_edit_page_permissions(self):
4155        """
4156        User can't edit page permissions if he
4157        does not have change permissions on the Page model,
4158        does not have change permissions on the PagePermission model,
4159        does not have global change permission,
4160        and/or does not have global change permissions permission.
4161        """
4162        page = self._permissions_page
4163        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4164        staff_user = self.get_staff_user_with_no_permissions()
4165        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4166
4167        permission = self.add_page_permission(
4168            user=staff_user_2,
4169            page=page,
4170            can_change_permissions=True
4171        )
4172
4173        data = self._get_page_permissions_data(
4174            page=page.pk,
4175            user=staff_user_2.pk,
4176            id=permission.pk,
4177            can_change_permissions=False,
4178        )
4179        data['_continue'] = '1'
4180
4181        self.add_permission(staff_user, 'change_page')
4182        self.add_permission(staff_user, 'change_pagepermission')
4183        self.add_page_permission(
4184            staff_user,
4185            page,
4186            can_change=True,
4187            can_change_permissions=False,
4188        )
4189
4190        with self.login_user_context(staff_user):
4191            response = self.client.post(endpoint, data)
4192            self.assertEqual(response.status_code, 403)
4193            self.assertFalse(
4194                self._page_permission_exists(
4195                    user=staff_user_2,
4196                    can_change_permissions=False,
4197                )
4198            )
4199
4200    def test_user_can_delete_page_permissions(self):
4201        """
4202        User can delete page permissions if he has
4203        change permissions on the Page model,
4204        delete permissions on the PagePermission model,
4205        global change permission and global change permissions permission.
4206        """
4207        page = self._permissions_page
4208        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4209        staff_user = self.get_staff_user_with_no_permissions()
4210        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4211        permission = self.add_page_permission(user=staff_user_2, page=page)
4212
4213        data = self._get_page_permissions_data(
4214            page=page.pk,
4215            user=staff_user_2.pk,
4216            id=permission.pk,
4217            DELETE='on',
4218        )
4219        data['_continue'] = '1'
4220
4221        self.add_permission(staff_user, 'change_page')
4222        self.add_permission(staff_user, 'delete_pagepermission')
4223        self.add_page_permission(
4224            staff_user,
4225            page,
4226            can_change=True,
4227            can_change_permissions=True,
4228        )
4229
4230        with self.login_user_context(staff_user):
4231            response = self.client.post(endpoint, data)
4232            self.assertEqual(response.status_code, 302)
4233            self.assertRedirects(response, endpoint)
4234            self.assertFalse(self._page_permission_exists(user=staff_user_2))
4235
4236    def test_user_cant_delete_page_permissions(self):
4237        """
4238        User can't delete page permissions if he
4239        does not have change permissions on the Page model,
4240        does not have delete permissions on the PagePermission model,
4241        does not have global change permission,
4242        and/or does not have global change permissions permission.
4243        """
4244        page = self._permissions_page
4245        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4246        staff_user = self.get_staff_user_with_no_permissions()
4247        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4248        permission = self.add_page_permission(user=staff_user_2, page=page)
4249
4250        data = self._get_page_permissions_data(
4251            page=page.pk,
4252            user=staff_user_2.pk,
4253            id=permission.pk,
4254            DELETE='on',
4255        )
4256        data['_continue'] = '1'
4257
4258        self.add_permission(staff_user, 'change_page')
4259        self.add_permission(staff_user, 'delete_pagepermission')
4260        self.add_page_permission(
4261            staff_user,
4262            page,
4263            can_change=True,
4264            can_change_permissions=False,
4265        )
4266
4267        with self.login_user_context(staff_user):
4268            response = self.client.post(endpoint, data)
4269            self.assertEqual(response.status_code, 403)
4270            self.assertTrue(self._page_permission_exists(user=staff_user_2))
4271
4272    def test_user_can_add_page_view_restrictions(self):
4273        """
4274        User can add page view restrictions if he has
4275        change permissions on the Page model,
4276        add permissions on the PagePermission model,
4277        global change permission and global change permissions permission.
4278        """
4279        page = self._permissions_page
4280        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4281        staff_user = self.get_staff_user_with_no_permissions()
4282        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4283
4284        data = self._get_page_view_restrictions_data(
4285            page=page.pk,
4286            user=staff_user_2.pk,
4287        )
4288        data['_continue'] = '1'
4289
4290        self.add_permission(staff_user, 'change_page')
4291        self.add_permission(staff_user, 'add_pagepermission')
4292        self.add_page_permission(
4293            staff_user,
4294            page,
4295            can_change=True,
4296            can_change_permissions=True,
4297        )
4298
4299        with self.login_user_context(staff_user):
4300            response = self.client.post(endpoint, data)
4301            self.assertEqual(response.status_code, 302)
4302            self.assertRedirects(response, endpoint)
4303            self.assertTrue(self._page_permission_exists(user=staff_user_2, can_view=True))
4304
4305    def test_user_cant_add_page_view_restrictions(self):
4306        """
4307        User can't add page view restrictions if he
4308        does not have change permissions on the Page model,
4309        does not have add permissions on the PagePermission model,
4310        does not have global change permission,
4311        and/or does not have global change permissions permission.
4312        """
4313        page = self._permissions_page
4314        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4315        staff_user = self.get_staff_user_with_no_permissions()
4316        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4317
4318        data = self._get_page_view_restrictions_data(
4319            page=page.pk,
4320            user=staff_user_2.pk,
4321        )
4322        data['_continue'] = '1'
4323
4324        self.add_permission(staff_user, 'change_page')
4325        self.add_permission(staff_user, 'add_pagepermission')
4326        self.add_page_permission(
4327            staff_user,
4328            page,
4329            can_change=True,
4330            can_change_permissions=False,
4331        )
4332
4333        with self.login_user_context(staff_user):
4334            response = self.client.post(endpoint, data)
4335            self.assertEqual(response.status_code, 403)
4336            self.assertFalse(self._page_permission_exists(user=staff_user_2, can_view=True))
4337
4338    def test_user_can_edit_page_view_restrictions(self):
4339        """
4340        User can edit page view restrictions if he has
4341        change permissions on the Page model,
4342        change permissions on the PagePermission model,
4343        global change permission and global change permissions permission.
4344        """
4345        page = self._permissions_page
4346        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4347        staff_user = self.get_staff_user_with_no_permissions()
4348        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4349
4350        permission = self.add_page_permission(
4351            user=staff_user_2,
4352            page=page,
4353            can_view=True,
4354            grant_on=1,
4355        )
4356
4357        data = model_to_dict(permission, exclude=['group'])
4358        data['grant_on'] = 5
4359
4360        data = self._get_page_view_restrictions_data(**data)
4361        data['_continue'] = '1'
4362
4363        self.add_permission(staff_user, 'change_page')
4364        self.add_permission(staff_user, 'change_pagepermission')
4365        self.add_page_permission(
4366            staff_user,
4367            page,
4368            can_change=True,
4369            can_change_permissions=True,
4370        )
4371
4372        with self.login_user_context(staff_user):
4373            response = self.client.post(endpoint, data)
4374            self.assertEqual(response.status_code, 302)
4375            self.assertRedirects(response, endpoint)
4376            self.assertTrue(
4377                self._page_permission_exists(
4378                    user=staff_user_2,
4379                    grant_on=5,
4380                )
4381            )
4382
4383    def test_user_cant_edit_page_view_restrictions(self):
4384        """
4385        User can't edit page view restrictions if he
4386        does not have change permissions on the Page model,
4387        does not have change permissions on the PagePermission model,
4388        does not have global change permission,
4389        and/or does not have global change permissions permission.
4390        """
4391        page = self._permissions_page
4392        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4393        staff_user = self.get_staff_user_with_no_permissions()
4394        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4395        permission = self.add_page_permission(
4396            user=staff_user_2,
4397            page=page,
4398            can_view=True,
4399            grant_on=1,
4400        )
4401
4402        data = model_to_dict(permission, exclude=['group'])
4403        data['grant_on'] = 5
4404
4405        data = self._get_page_view_restrictions_data(**data)
4406        data['_continue'] = '1'
4407
4408        self.add_permission(staff_user, 'change_page')
4409        self.add_permission(staff_user, 'change_pagepermission')
4410        self.add_page_permission(
4411            staff_user,
4412            page,
4413            can_change=True,
4414            can_change_permissions=False,
4415        )
4416
4417        with self.login_user_context(staff_user):
4418            response = self.client.post(endpoint, data)
4419            self.assertEqual(response.status_code, 403)
4420            self.assertFalse(
4421                self._page_permission_exists(
4422                    user=staff_user_2,
4423                    grant_on=5,
4424                )
4425            )
4426
4427    def test_user_can_delete_page_view_restrictions(self):
4428        """
4429        User can delete view restrictions if he has
4430        change permissions on the Page model,
4431        delete permissions on the PagePermission model,
4432        global change permission and global change permissions permission.
4433        """
4434        page = self._permissions_page
4435        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4436        staff_user = self.get_staff_user_with_no_permissions()
4437        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4438        permission = self.add_page_permission(
4439            user=staff_user_2,
4440            page=page,
4441            can_view=True,
4442        )
4443
4444        data = model_to_dict(permission, exclude=['group'])
4445        data['DELETE'] = True
4446
4447        data = self._get_page_view_restrictions_data(**data)
4448        data['_continue'] = '1'
4449
4450        self.add_permission(staff_user, 'change_page')
4451        self.add_permission(staff_user, 'delete_pagepermission')
4452        self.add_page_permission(
4453            staff_user,
4454            page,
4455            can_change=True,
4456            can_change_permissions=True,
4457        )
4458
4459        with self.login_user_context(staff_user):
4460            response = self.client.post(endpoint, data)
4461            self.assertEqual(response.status_code, 302)
4462            self.assertRedirects(response, endpoint)
4463            self.assertFalse(self._page_permission_exists(user=staff_user_2, can_view=True))
4464
4465    def test_user_cant_delete_page_view_restrictions(self):
4466        """
4467        User can't delete view restrictions if he
4468        does not have change permissions on the Page model,
4469        does not have delete permissions on the PagePermission model,
4470        does not have global change permission,
4471        and/or does not have global change permissions permission.
4472        """
4473        page = self._permissions_page
4474        endpoint = self.get_admin_url(Page, 'permissions', page.pk) + '?language=en'
4475        staff_user = self.get_staff_user_with_no_permissions()
4476        staff_user_2 = self.get_staff_page_user(created_by=staff_user)
4477        permission = self.add_page_permission(
4478            user=staff_user_2,
4479            page=page,
4480            can_view=True,
4481        )
4482
4483        data = model_to_dict(permission, exclude=['group'])
4484        data['DELETE'] = True
4485
4486        data = self._get_page_view_restrictions_data(**data)
4487        data['_continue'] = '1'
4488
4489        self.add_permission(staff_user, 'change_page')
4490        self.add_permission(staff_user, 'delete_pagepermission')
4491        self.add_page_permission(
4492            staff_user,
4493            page,
4494            can_change=True,
4495            can_change_permissions=False,
4496        )
4497
4498        with self.login_user_context(staff_user):
4499            response = self.client.post(endpoint, data)
4500            self.assertEqual(response.status_code, 403)
4501            self.assertTrue(self._page_permission_exists(user=staff_user_2, can_view=True))
4502
4503    def test_user_can_edit_title_fields(self):
4504        """
4505        User can edit title (translation) fields if he has
4506        global change permissions.
4507        """
4508        page = self._permissions_page
4509        staff_user = self.get_staff_user_with_no_permissions()
4510        title = self._add_translation_to_page(page)
4511        endpoint = self.get_admin_url(Page, 'edit_title_fields', page.pk, title.language)
4512
4513        self.add_page_permission(
4514            staff_user,
4515            page,
4516            can_change=True,
4517        )
4518        self.add_permission(staff_user, 'change_page')
4519
4520        with self.login_user_context(staff_user):
4521            data = model_to_dict(title, fields=['title'])
4522            data['title'] = 'permissions-de-2'
4523
4524            response = self.client.post(endpoint, data)
4525            self.assertEqual(response.status_code, 200)
4526            self.assertTrue(self._translation_exists(title='permissions-de-2'))
4527
4528    def test_user_cant_edit_title_fields(self):
4529        """
4530        User can't edit title (translation) fields if he does not have
4531        global change permissions.
4532        """
4533        page = self._permissions_page
4534        staff_user = self.get_staff_user_with_no_permissions()
4535        title = self._add_translation_to_page(page)
4536        endpoint = self.get_admin_url(Page, 'edit_title_fields', page.pk, title.language)
4537
4538        self.add_page_permission(
4539            staff_user,
4540            page,
4541            can_change=False,
4542        )
4543        self.add_permission(staff_user, 'change_page')
4544
4545        with self.login_user_context(staff_user):
4546            data = model_to_dict(title, fields=['title'])
4547            data['title'] = 'permissions-de-2'
4548
4549            response = self.client.post(endpoint, data)
4550            self.assertEqual(response.status_code, 403)
4551            self.assertFalse(self._translation_exists(title='permissions-de-2'))
4552
4553    # Plugin related tests
4554
4555    def test_user_can_add_plugin(self):
4556        """
4557        User can add a plugin if he has change permissions
4558        on the Page model, add permissions on the plugin model
4559        and global change permissions.
4560        """
4561        page = self._permissions_page
4562        staff_user = self.get_staff_user_with_no_permissions()
4563        placeholder = page.placeholders.get(slot='body')
4564        plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin')
4565        endpoint = self._get_add_plugin_uri(page)
4566
4567        self.add_permission(staff_user, 'change_page')
4568        self.add_permission(staff_user, 'add_link')
4569        self.add_page_permission(
4570            staff_user,
4571            page,
4572            can_change=True,
4573        )
4574
4575        with self.login_user_context(staff_user):
4576            data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}
4577            response = self.client.post(endpoint, data)
4578            self.assertEqual(response.status_code, 200)
4579            self.assertEqual(plugins.count(), 1)
4580
4581    def test_user_cant_add_plugin(self):
4582        """
4583        User can't add a plugin if he
4584        does not have change permissions on the Page model,
4585        does not have add permissions on the plugin model
4586        and/or does not have global change permissions.
4587        """
4588        page = self._permissions_page
4589        staff_user = self.get_staff_user_with_no_permissions()
4590        placeholder = page.placeholders.get(slot='body')
4591        plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin')
4592        endpoint = self._get_add_plugin_uri(page)
4593
4594        self.add_permission(staff_user, 'change_page')
4595        self.add_permission(staff_user, 'add_link')
4596        self.add_page_permission(
4597            staff_user,
4598            page,
4599            can_change=False,
4600        )
4601
4602        with self.login_user_context(staff_user):
4603            data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}
4604            response = self.client.post(endpoint, data)
4605            self.assertEqual(response.status_code, 403)
4606            self.assertEqual(plugins.count(), 0)
4607
4608    def test_user_can_edit_plugin(self):
4609        """
4610        User can edit a plugin if he has change permissions
4611        on the Page model, change permissions on the plugin model
4612        and global change permissions.
4613        """
4614        page = self._permissions_page
4615        staff_user = self.get_staff_user_with_no_permissions()
4616        plugin = self._add_plugin_to_page(page)
4617        endpoint = self.get_change_plugin_uri(plugin)
4618
4619        self.add_permission(staff_user, 'change_page')
4620        self.add_permission(staff_user, 'change_link')
4621        self.add_page_permission(
4622            staff_user,
4623            page,
4624            can_change=True,
4625        )
4626
4627        with self.login_user_context(staff_user):
4628            data = model_to_dict(plugin, fields=['name', 'external_link'])
4629            data['name'] = 'A link 2'
4630
4631            response = self.client.post(endpoint, data)
4632            self.assertEqual(response.status_code, 200)
4633            plugin.refresh_from_db()
4634            self.assertEqual(plugin.name, data['name'])
4635
4636    def test_user_cant_edit_plugin(self):
4637        """
4638        User can't edit a plugin if he
4639        does not have change permissions on the Page model,
4640        does not have change permissions on the plugin model
4641        and/or does not have global change permissions.
4642        """
4643        page = self._permissions_page
4644        staff_user = self.get_staff_user_with_no_permissions()
4645        plugin = self._add_plugin_to_page(page)
4646        endpoint = self.get_change_plugin_uri(plugin)
4647
4648        self.add_permission(staff_user, 'change_page')
4649        self.add_permission(staff_user, 'change_link')
4650        self.add_page_permission(
4651            staff_user,
4652            page,
4653            can_change=False,
4654        )
4655
4656        with self.login_user_context(staff_user):
4657            data = model_to_dict(plugin, fields=['name', 'external_link'])
4658            data['name'] = 'A link 2'
4659
4660            response = self.client.post(endpoint, data)
4661            self.assertEqual(response.status_code, 403)
4662            plugin.refresh_from_db()
4663            self.assertNotEqual(plugin.name, data['name'])
4664
4665    def test_user_can_delete_plugin(self):
4666        """
4667        User can delete a plugin if he has change permissions
4668        on the Page model, delete permissions on the plugin model
4669        and global change permissions.
4670        """
4671        page = self._permissions_page
4672        staff_user = self.get_staff_user_with_no_permissions()
4673        plugin = self._add_plugin_to_page(page)
4674        endpoint = self.get_delete_plugin_uri(plugin)
4675
4676        self.add_permission(staff_user, 'change_page')
4677        self.add_permission(staff_user, 'delete_link')
4678        self.add_page_permission(
4679            staff_user,
4680            page,
4681            can_change=True,
4682        )
4683
4684        with self.login_user_context(staff_user):
4685            data = {'post': True}
4686
4687            response = self.client.post(endpoint, data)
4688            self.assertEqual(response.status_code, 302)
4689            self.assertFalse(CMSPlugin.objects.filter(pk=plugin.pk).exists())
4690
4691    def test_user_cant_delete_plugin(self):
4692        """
4693        User can't delete a plugin if he
4694        does not have change permissions on the Page model,
4695        does not have delete permissions on the plugin model
4696        and/or does not have global change permissions.
4697        """
4698        page = self._permissions_page
4699        staff_user = self.get_staff_user_with_no_permissions()
4700        plugin = self._add_plugin_to_page(page)
4701        endpoint = self.get_delete_plugin_uri(plugin)
4702
4703        self.add_permission(staff_user, 'change_page')
4704        self.add_permission(staff_user, 'delete_link')
4705        self.add_page_permission(
4706            staff_user,
4707            page,
4708            can_change=False,
4709        )
4710
4711        with self.login_user_context(staff_user):
4712            data = {'post': True}
4713
4714            response = self.client.post(endpoint, data)
4715            self.assertEqual(response.status_code, 403)
4716            self.assertTrue(CMSPlugin.objects.filter(pk=plugin.pk).exists())
4717
4718    def test_user_can_move_plugin(self):
4719        """
4720        User can move a plugin if he has change permissions
4721        on the Page model, change permissions on the plugin model
4722        and global change permissions.
4723        """
4724        page = self._permissions_page
4725        staff_user = self.get_staff_user_with_no_permissions()
4726        plugin = self._add_plugin_to_page(page)
4727        endpoint = self.get_move_plugin_uri(plugin)
4728        source_placeholder = plugin.placeholder
4729        target_placeholder = page.placeholders.get(slot='right-column')
4730
4731        data = {
4732            'plugin_id': plugin.pk,
4733            'target_language': 'en',
4734            'placeholder_id': target_placeholder.pk,
4735            'plugin_parent': '',
4736        }
4737
4738        self.add_permission(staff_user, 'change_page')
4739        self.add_permission(staff_user, 'change_link')
4740        self.add_page_permission(
4741            staff_user,
4742            page,
4743            can_change=True,
4744        )
4745
4746        with self.login_user_context(staff_user):
4747            response = self.client.post(endpoint, data)
4748            self.assertEqual(response.status_code, 200)
4749            self.assertTrue(target_placeholder.get_plugins('en').filter(pk=plugin.pk))
4750            self.assertFalse(source_placeholder.get_plugins('en').filter(pk=plugin.pk))
4751
4752    def test_user_cant_move_plugin(self):
4753        """
4754        User can't move a plugin if he
4755        does not have change permissions on the Page model,
4756        does not have change permissions on the plugin model
4757        and/or does not have global change permissions.
4758        """
4759        page = self._permissions_page
4760        staff_user = self.get_staff_user_with_no_permissions()
4761        plugin = self._add_plugin_to_page(page)
4762        endpoint = self.get_move_plugin_uri(plugin)
4763        source_placeholder = plugin.placeholder
4764        target_placeholder = page.placeholders.get(slot='right-column')
4765
4766        data = {
4767            'plugin_id': plugin.pk,
4768            'target_language': 'en',
4769            'placeholder_id': target_placeholder.pk,
4770            'plugin_parent': '',
4771        }
4772
4773        self.add_permission(staff_user, 'change_page')
4774        self.add_permission(staff_user, 'change_link')
4775        self.add_page_permission(
4776            staff_user,
4777            page,
4778            can_change=False,
4779        )
4780
4781        with self.login_user_context(staff_user):
4782            response = self.client.post(endpoint, data)
4783            self.assertEqual(response.status_code, 403)
4784            self.assertFalse(target_placeholder.get_plugins('en').filter(pk=plugin.pk))
4785            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk))
4786
4787    def test_user_can_copy_plugin(self):
4788        """
4789        User can copy a plugin if he has change permissions
4790        on the Page model, add permissions on the plugin model
4791        and global change permissions.
4792        """
4793        page = self._permissions_page
4794        staff_user = self.get_staff_user_with_no_permissions()
4795        plugin = self._add_plugin_to_page(page)
4796        translation = self._add_translation_to_page(page)
4797        endpoint = self.get_copy_plugin_uri(plugin)
4798        source_placeholder = plugin.placeholder
4799        target_placeholder = page.placeholders.get(slot='right-column')
4800
4801        data = {
4802            'source_plugin_id': plugin.pk,
4803            'source_placeholder_id': source_placeholder.pk,
4804            'source_language': plugin.language,
4805            'target_language': translation.language,
4806            'target_placeholder_id': target_placeholder.pk,
4807        }
4808
4809        self.add_permission(staff_user, 'change_page')
4810        self.add_permission(staff_user, 'add_link')
4811        self.add_page_permission(
4812            staff_user,
4813            page,
4814            can_change=True,
4815        )
4816
4817        with self.login_user_context(staff_user):
4818            response = self.client.post(endpoint, data)
4819            self.assertEqual(response.status_code, 200)
4820            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists())
4821            self.assertTrue(
4822                target_placeholder
4823                .get_plugins(translation.language)
4824                .filter(plugin_type=plugin.plugin_type)
4825                .exists()
4826            )
4827
4828    def test_user_cant_copy_plugin(self):
4829        """
4830        User can't copy a plugin if he
4831        does not have change permissions on the Page model,
4832        does not have add permissions on the plugin model,
4833        and/or does not have global change permissions.
4834        """
4835        page = self._permissions_page
4836        staff_user = self.get_staff_user_with_no_permissions()
4837        plugin = self._add_plugin_to_page(page)
4838        translation = self._add_translation_to_page(page)
4839        endpoint = self.get_copy_plugin_uri(plugin)
4840        source_placeholder = plugin.placeholder
4841        target_placeholder = page.placeholders.get(slot='right-column')
4842
4843        data = {
4844            'source_plugin_id': plugin.pk,
4845            'source_placeholder_id': source_placeholder.pk,
4846            'source_language': plugin.language,
4847            'target_language': translation.language,
4848            'target_placeholder_id': target_placeholder.pk,
4849        }
4850
4851        self.add_permission(staff_user, 'change_page')
4852        self.add_permission(staff_user, 'add_link')
4853        self.add_page_permission(
4854            staff_user,
4855            page,
4856            can_change=False,
4857        )
4858
4859        with self.login_user_context(staff_user):
4860            response = self.client.post(endpoint, data)
4861            self.assertEqual(response.status_code, 403)
4862            self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists())
4863            self.assertFalse(
4864                target_placeholder
4865                .get_plugins(translation.language)
4866                .filter(plugin_type=plugin.plugin_type)
4867                .exists()
4868            )
4869
4870    def test_user_can_copy_plugins_to_language(self):
4871        """
4872        User can copy all plugins to another language if he has
4873        change permissions on the Page model, add permissions on the
4874        plugins being copied and global change permissions.
4875        """
4876        page = self._permissions_page
4877        staff_user = self.get_staff_user_with_no_permissions()
4878        translation = self._add_translation_to_page(page)
4879        endpoint = self.get_admin_url(Page, 'copy_language', page.pk)
4880        plugins = [
4881            self._add_plugin_to_page(page),
4882            self._add_plugin_to_page(page),
4883            self._add_plugin_to_page(page),
4884            self._add_plugin_to_page(page),
4885        ]
4886        placeholder = plugins[0].placeholder
4887
4888        data = {
4889            'source_language': 'en',
4890            'target_language': translation.language,
4891        }
4892
4893        self.add_permission(staff_user, 'change_page')
4894        self.add_permission(staff_user, 'add_link')
4895        self.add_page_permission(
4896            staff_user,
4897            page,
4898            can_change=True,
4899        )
4900
4901        with self.login_user_context(staff_user):
4902            response = self.client.post(endpoint, data)
4903            self.assertEqual(response.status_code, 200)
4904            new_plugins = placeholder.get_plugins(translation.language)
4905            self.assertEqual(new_plugins.count(), len(plugins))
4906
4907    def test_user_cant_copy_plugins_to_language(self):
4908        """
4909        User can't copy all plugins to another language if he does have
4910        change permissions on the Page model, does not have add permissions
4911        on the plugins being copied and/or does not have global
4912        change permissions.
4913        """
4914        page = self._permissions_page
4915        staff_user = self.get_staff_user_with_no_permissions()
4916        translation = self._add_translation_to_page(page)
4917        endpoint = self.get_admin_url(Page, 'copy_language', page.pk)
4918        plugins = [
4919            self._add_plugin_to_page(page),
4920            self._add_plugin_to_page(page),
4921            self._add_plugin_to_page(page),
4922            self._add_plugin_to_page(page),
4923        ]
4924        placeholder = plugins[0].placeholder
4925
4926        data = {
4927            'source_language': 'en',
4928            'target_language': translation.language,
4929        }
4930
4931        self.add_permission(staff_user, 'change_page')
4932        self.add_permission(staff_user, 'add_link')
4933        self.add_page_permission(
4934            staff_user,
4935            page,
4936            can_change=False,
4937        )
4938
4939        with self.login_user_context(staff_user):
4940            response = self.client.post(endpoint, data)
4941            self.assertEqual(response.status_code, 403)
4942            new_plugins = placeholder.get_plugins(translation.language)
4943            self.assertEqual(new_plugins.count(), 0)
4944
4945    # Placeholder related tests
4946
4947    def test_user_can_clear_empty_placeholder(self):
4948        """
4949        User can clear an empty placeholder if he has change permissions
4950        on the Page model and global change permissions.
4951        """
4952        page = self._permissions_page
4953        staff_user = self.get_staff_user_with_no_permissions()
4954        placeholder = page.placeholders.get(slot='body')
4955        endpoint = self.get_clear_placeholder_url(placeholder)
4956
4957        self.add_permission(staff_user, 'change_page')
4958        self.add_global_permission(staff_user, can_change=True)
4959
4960        with self.login_user_context(staff_user):
4961            response = self.client.post(endpoint, {'test': 0})
4962            self.assertEqual(response.status_code, 302)
4963
4964    def test_user_cant_clear_empty_placeholder(self):
4965        """
4966        User can't clear an empty placeholder if he does not have
4967        change permissions on the Page model and/or does not have
4968        global change permissions.
4969        """
4970        page = self._permissions_page
4971        staff_user = self.get_staff_user_with_no_permissions()
4972        placeholder = page.placeholders.get(slot='body')
4973        endpoint = self.get_clear_placeholder_url(placeholder)
4974
4975        self.add_permission(staff_user, 'change_page')
4976        self.add_global_permission(staff_user, can_change=False)
4977
4978        with self.login_user_context(staff_user):
4979            response = self.client.post(endpoint, {'test': 0})
4980            self.assertEqual(response.status_code, 403)
4981
4982    def test_user_can_clear_non_empty_placeholder(self):
4983        """
4984        User can clear a placeholder with plugins if he has
4985        change permissions on the Page model, delete permissions
4986        on the plugin models in the placeholder and global change permissions.
4987        """
4988        page = self._permissions_page
4989        staff_user = self.get_staff_user_with_no_permissions()
4990        plugins = [
4991            self._add_plugin_to_page(page, 'TextPlugin'),
4992            self._add_plugin_to_page(page, 'LinkPlugin'),
4993        ]
4994        placeholder = plugins[0].placeholder
4995        endpoint = self.get_clear_placeholder_url(placeholder)
4996
4997        self.add_permission(staff_user, 'delete_text')
4998        self.add_permission(staff_user, 'delete_link')
4999        self.add_permission(staff_user, 'change_page')
5000        self.add_global_permission(staff_user, can_change=True)
5001
5002        with self.login_user_context(staff_user):
5003            response = self.client.post(endpoint, {'test': 0})
5004            self.assertEqual(response.status_code, 302)
5005            self.assertEqual(placeholder.get_plugins('en').count(), 0)
5006
5007    def test_user_cant_clear_non_empty_placeholder(self):
5008        """
5009        User can't clear a placeholder with plugins if he does not have
5010        change permissions on the Page model, does not have delete
5011        permissions on the plugin models in the placeholder and/or
5012        does not have global change permissions.
5013        """
5014        page = self._permissions_page
5015        staff_user = self.get_staff_user_with_no_permissions()
5016        plugins = [
5017            self._add_plugin_to_page(page, 'TextPlugin'),
5018            self._add_plugin_to_page(page, 'LinkPlugin'),
5019        ]
5020        placeholder = plugins[0].placeholder
5021        endpoint = self.get_clear_placeholder_url(placeholder)
5022
5023        self.add_permission(staff_user, 'delete_text')
5024        self.add_permission(staff_user, 'delete_link')
5025        self.add_permission(staff_user, 'change_page')
5026        self.add_global_permission(staff_user, can_change=False)
5027
5028        with self.login_user_context(staff_user):
5029            response = self.client.post(endpoint, {'test': 0})
5030            self.assertEqual(response.status_code, 403)
5031            self.assertEqual(placeholder.get_plugins('en').count(), 2)
5032
5033
5034@override_settings(CMS_PERMISSION=False)
5035class PermissionsOffTest(PermissionsTestCase):
5036    """
5037    Tests all user interactions with the page admin
5038    while permissions are set to False.
5039    """
5040
5041
5042@override_settings(ROOT_URLCONF='cms.test_utils.project.noadmin_urls')
5043class NoAdminPageTests(CMSTestCase):
5044
5045    def test_get_page_from_request_fakeadmin_nopage(self):
5046        noadmin_apps = [app for app in installed_apps() if app != 'django.contrib.admin']
5047        with self.settings(INSTALLED_APPS=noadmin_apps):
5048            request = self.get_request('/en/admin/')
5049            page = get_page_from_request(request)
5050            self.assertEqual(page, None)
5051