import json from django.conf import settings from django.contrib import admin from django.contrib.admin.sites import site from django.contrib.admin.utils import flatten_fieldsets from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission from django.contrib.sites.models import Site from django.http import Http404, HttpResponseBadRequest, HttpResponseNotFound from django.test.utils import override_settings from django.utils.encoding import force_str, smart_str from djangocms_text.cms_plugins import TextPlugin from djangocms_text.models import Text from cms import api from cms.admin.forms import ChangePageForm from cms.api import add_plugin, create_page, create_page_content from cms.constants import TEMPLATE_INHERITANCE_MAGIC from cms.models import PageContent, PageUrl, UserSettings from cms.models.pagemodel import Page from cms.models.permissionmodels import GlobalPagePermission, PagePermission from cms.models.placeholdermodel import Placeholder from cms.test_utils import testcases as base from cms.test_utils.testcases import ( URL_CMS_PAGE_DELETE, URL_CMS_PAGE_PUBLISHED, CMSTestCase, ) from cms.toolbar.utils import get_object_edit_url from cms.utils.conf import get_cms_setting from cms.utils.i18n import get_language_list from cms.utils.urlutils import admin_reverse class AdminTestsBase(CMSTestCase): @property def page_admin_class(self): return site._registry[Page] @property def pagecontent_admin_class(self): return site._registry[PageContent] def _get_guys(self, admin_only=False, use_global_permissions=True): admin_user = self.get_superuser() if admin_only: return admin_user staff_user = self._get_staff_user(use_global_permissions) return admin_user, staff_user def _get_staff_user(self, use_global_permissions=True): USERNAME = "test" if get_user_model().USERNAME_FIELD == "email": normal_guy = get_user_model().objects.create_user(USERNAME, "test@test.com", "test@test.com") else: normal_guy = get_user_model().objects.create_user(USERNAME, "test@test.com", USERNAME) normal_guy.is_staff = True normal_guy.is_active = True perms = Permission.objects.filter( codename__in=["change_page", "change_title", "add_page", "add_title", "delete_page", "delete_title"] ) normal_guy.save() normal_guy.user_permissions.set(perms) if use_global_permissions: gpp = GlobalPagePermission.objects.create( user=normal_guy, can_change=True, can_delete=True, can_publish=True, can_change_advanced_settings=False, can_change_permissions=False, can_move_page=True, ) gpp.sites.set(Site.objects.all()) return normal_guy class AdminTestCase(AdminTestsBase): def test_extension_not_in_admin(self): admin_user, staff = self._get_guys() with self.login_user_context(admin_user): request = self.get_request(self.get_pages_admin_list_uri("en")) response = site.index(request) self.assertNotContains(response, "/mytitleextension/") self.assertNotContains(response, "/mypageextension/") @override_settings(CMS_PERMISSION=False) def test_2apphooks_with_same_namespace(self): PAGE1 = "Test Page" PAGE2 = "Test page 2" APPLICATION_URLS = "project.sampleapp.urls" admin_user, normal_guy = self._get_guys() current_site = Site.objects.get(pk=1) # The admin creates the page page = create_page(PAGE1, "nav_playground.html", "en", site=current_site, created_by=admin_user) page2 = create_page(PAGE2, "nav_playground.html", "en", site=current_site, created_by=admin_user) page.application_urls = APPLICATION_URLS page.application_namespace = "space1" page.save() page2.application_urls = APPLICATION_URLS page2.save() # The admin edits the page (change the page name for ex.) page_data = { "title": PAGE2, "slug": page2.get_slug("en"), "template": page2.template, "application_urls": "SampleApp", "application_namespace": "space1", } with self.login_user_context(admin_user): resp = self.client.post(base.URL_CMS_PAGE_ADVANCED_CHANGE % page.pk, page_data) self.assertEqual(resp.status_code, 302) self.assertEqual(Page.objects.filter(application_namespace="space1").count(), 1) resp = self.client.post(base.URL_CMS_PAGE_ADVANCED_CHANGE % page2.pk, page_data) self.assertEqual(resp.status_code, 200) page_data["application_namespace"] = "space2" resp = self.client.post(base.URL_CMS_PAGE_ADVANCED_CHANGE % page2.pk, page_data) self.assertEqual(resp.status_code, 302) def test_delete(self): admin_user = self.get_superuser() create_page("home", "nav_playground.html", "en", created_by=admin_user) page = create_page("delete-page", "nav_playground.html", "en", created_by=admin_user) create_page("child-page", "nav_playground.html", "en", created_by=admin_user, parent=page) body = page.get_placeholders("en").get(slot="body") add_plugin(body, "TextPlugin", "en", body="text") with self.login_user_context(admin_user): data = {"post": "yes"} response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data, follow=True) self.assertRedirects(response, self.get_pages_admin_list_uri("en")) def test_delete_diff_language(self): admin_user = self.get_superuser() create_page("home", "nav_playground.html", "en", created_by=admin_user) page = create_page("delete-page", "nav_playground.html", "en", created_by=admin_user) create_page("child-page", "nav_playground.html", "de", created_by=admin_user, parent=page) body = page.get_placeholders("en").get(slot="body") add_plugin(body, "TextPlugin", "en", body="text") with self.login_user_context(admin_user): data = {"post": "yes"} response = self.client.post(URL_CMS_PAGE_DELETE % page.pk, data, follow=True) # follow=True, since page changelist redirects to page content changelist self.assertRedirects(response, self.get_pages_admin_list_uri("en")) def test_search_fields(self): superuser = self.get_superuser() from django.contrib.admin import site with self.login_user_context(superuser): for model, admin_instance in site._registry.items(): if model._meta.app_label != "cms": continue if not admin_instance.search_fields: continue url = admin_reverse("cms_%s_changelist" % model._meta.model_name) response = self.client.get("%s?q=1" % url, follow=True) # Page redirects to PageContent errmsg = response.content self.assertEqual(response.status_code, 200, errmsg) def test_pagetree_filtered(self): superuser = self.get_superuser() create_page("root-page", "nav_playground.html", "en", created_by=superuser) with self.login_user_context(superuser): url = admin_reverse("cms_pagecontent_changelist") response = self.client.get("%s?template__exact=nav_playground.html" % url) errmsg = response.content self.assertEqual(response.status_code, 200, errmsg) def test_create_translation_copies_template(self): admin_user = self.get_superuser() page = create_page("create-translation", "col_two.html", "de", created_by=admin_user) with self.login_user_context(admin_user): response = self.client.post( self.get_page_add_uri("en", page), data={"title": "create-translation-en", "slug": "create-translation-en", "cms_page": page.pk}, ) self.assertRedirects(response, self.get_pages_admin_list_uri("en")) self.assertEqual(page.get_content_obj("en").template, "col_two.html") def test_create_translation_copies_template_on_default_page_language_update(self): admin_user = self.get_superuser() page = create_page("create-translation", "nav_playground.html", "en", created_by=admin_user) with self.login_user_context(admin_user): data = {"title": "test page 2", "slug": "page-test-2", "template": "col_two.html"} self.client.post( self.get_page_change_uri("en", page), data=data, ) response = self.client.post( self.get_page_add_uri("de", page), data={"title": "create-translation-de", "slug": "create-translation-de", "cms_page": page.pk}, ) self.assertRedirects(response, self.get_pages_admin_list_uri("de")) self.assertEqual(page.get_content_obj("de").template, "col_two.html") def test_create_translation_copies_template_with_inheritance(self): """ Test that template inheritance flag is properly copied when creating translations """ admin_user = self.get_superuser() page = create_page("inherit-template", "nav_playground.html", "en", created_by=admin_user) with self.login_user_context(admin_user): data = {"title": "test page", "slug": "test-page", "template": TEMPLATE_INHERITANCE_MAGIC} self.client.post( self.get_page_change_uri("en", page), data=data, ) response = self.client.post( self.get_page_add_uri("de", page), data={"title": "inherit-de", "slug": "inherit-de", "cms_page": page.pk}, ) self.assertRedirects(response, self.get_pages_admin_list_uri("de")) self.assertEqual(page.get_content_obj("de").template, TEMPLATE_INHERITANCE_MAGIC) def test_create_translation_always_copies_template_from_default_language_regardless_of_amount_of_languages(self): admin_user = self.get_superuser() # Create a page in default language ("fr") page = create_page("create-translation", "nav_playground.html", "fr", created_by=admin_user) with self.login_user_context(admin_user): data = { "title": "create-translation-de", "slug": "create-translation-de", "cms_page": page.pk, "template": "col_two.html", } response = self.client.post( self.get_page_add_uri("de", page), data=data, ) data = {"title": "create-translation-en", "slug": "create-translation-en", "cms_page": page.pk} response = self.client.post( self.get_page_add_uri("en", page), data=data, ) self.assertRedirects(response, self.get_pages_admin_list_uri("en")) self.assertEqual(page.get_content_obj("en").template, "nav_playground.html") def test_delete_translation(self): admin_user = self.get_superuser() page = create_page("delete-page-translation", "nav_playground.html", "en", created_by=admin_user) create_page_content("de", "delete-page-translation-2", page, slug="delete-page-translation-2") create_page_content("es-mx", "delete-page-translation-es", page, slug="delete-page-translation-es") data = {"post": "yes"} with self.login_user_context(admin_user): response = self.client.get(self.get_page_delete_translation_uri("de", page)) self.assertEqual(response.status_code, 200) response = self.client.post(self.get_page_delete_translation_uri("de", page), data=data) self.assertRedirects(response, self.get_pages_admin_list_uri("de")) response = self.client.get(self.get_page_delete_translation_uri("es-mx", page)) self.assertEqual(response.status_code, 200) self.assertContains( response, '

Are you sure you want to delete the page content "delete-page-translation-es (es-mx)"?' ) response = self.client.post(self.get_page_delete_translation_uri("es-mx", page), data=data) self.assertRedirects(response, self.get_pages_admin_list_uri("es-mx")) self.assertTrue(PageContent.objects.filter(page=page, language="en").exists()) self.assertFalse(PageContent.objects.filter(page=page, language="de").exists()) self.assertFalse(PageContent.objects.filter(page=page, language="es-mx").exists()) self.assertFalse(PageUrl.objects.filter(page=page, language="de").exists()) self.assertFalse(PageUrl.objects.filter(page=page, language="es-mx").exists()) def test_delete_translation_without_page_url(self): # A translation may exist without a PageUrl (e.g., never published with versioning) admin_user = self.get_superuser() page = create_page("delete-page-translation", "nav_playground.html", "en", created_by=admin_user) create_page_content("de", "delete-page-translation-de", page, slug="delete-page-translation-de") PageUrl.objects.filter(page=page, language="de").delete() with self.login_user_context(admin_user): response = self.client.post(self.get_page_delete_translation_uri("de", page), data={"post": "yes"}) self.assertRedirects(response, self.get_pages_admin_list_uri("de")) self.assertTrue(PageContent.objects.filter(page=page, language="en").exists()) self.assertTrue(PageUrl.objects.filter(page=page, language="en").exists()) self.assertFalse(PageContent.objects.filter(page=page, language="de").exists()) def test_change_template(self): template = get_cms_setting("TEMPLATES")[0][0] admin_user, staff = (self.get_superuser(), self.get_staff_user_with_no_permissions()) with self.login_user_context(admin_user): response = self.client.post(self.get_admin_url(PageContent, "change_template", 1), {"template": template}) self.assertEqual(response.status_code, 404) with self.login_user_context(staff): response = self.client.post(self.get_admin_url(PageContent, "change_template", 1), {"template": template}) self.assertEqual(response.status_code, 403) page = create_page("test-page", template, "en") endpoint = self.get_page_change_template_uri("en", page) with self.login_user_context(staff): response = self.client.post(endpoint, {"template": template}) self.assertEqual(response.status_code, 403) with self.login_user_context(admin_user): response = self.client.post(endpoint, {"template": "doesntexist"}) self.assertEqual(response.status_code, 400) response = self.client.post(endpoint, {"template": template}) self.assertEqual(response.status_code, 200) def test_changelist_items(self): admin_user = self.get_superuser() first_level_page = create_page("level1", "nav_playground.html", "en") second_level_page_top = create_page( "level21", "nav_playground.html", "en", created_by=admin_user, parent=first_level_page ) first_level_page.refresh_from_db() second_level_page_bottom = create_page( "level22", "nav_playground.html", "en", created_by=admin_user, parent=first_level_page ) third_level_page = create_page( "level3", "nav_playground.html", "en", created_by=admin_user, parent=second_level_page_top ) self.assertEqual(Page.objects.all().count(), 4) with self.login_user_context(admin_user): response = self.client.get(self.get_pages_admin_list_uri("en")) cms_page_nodes = response.context_data["tree"]["items"] self.assertEqual(cms_page_nodes[0], first_level_page) self.assertEqual(cms_page_nodes[1], second_level_page_top) self.assertEqual(cms_page_nodes[2], third_level_page) self.assertEqual(cms_page_nodes[3], second_level_page_bottom) def test_changelist_get_results(self): admin_user = self.get_superuser() first_level_page = create_page("level1", "nav_playground.html", "en") second_level_page_top = create_page( "level21", "nav_playground.html", "en", created_by=admin_user, parent=first_level_page ) create_page( "level22", "nav_playground.html", "en", created_by=admin_user, parent=self.reload(first_level_page) ) create_page("level3", "nav_playground.html", "en", created_by=admin_user, parent=second_level_page_top) create_page( "level23", "nav_playground.html", "en", created_by=admin_user, parent=self.reload(first_level_page) ) self.assertEqual(Page.objects.all().count(), 5) endpoint = self.get_pages_admin_list_uri() with self.login_user_context(admin_user): response = self.client.get(endpoint) self.assertEqual(response.context_data["tree"]["items"].count(), 5) with self.login_user_context(admin_user): response = self.client.get(endpoint + "&q=level23") self.assertEqual(response.context_data["tree"]["items"].count(), 1) with self.login_user_context(admin_user): response = self.client.get(endpoint + "&q=level2") self.assertEqual(response.context_data["tree"]["items"].count(), 3) def test_empty_placeholder_with_nested_plugins(self): # It's important that this test clears a placeholder # which only has nested plugins. # This allows us to catch a strange bug that happened # under these conditions with the new related name handling. page_en = create_page("EmptyPlaceholderTestPage (EN)", "nav_playground.html", "en") ph = page_en.get_placeholders("en").get(slot="body") column_wrapper = add_plugin(ph, "MultiColumnPlugin", "en") add_plugin(ph, "ColumnPlugin", "en", parent=column_wrapper) add_plugin(ph, "ColumnPlugin", "en", parent=column_wrapper) # before cleaning the de placeholder self.assertEqual(ph.get_plugins("en").count(), 3) admin_user, staff = self._get_guys() endpoint = self.get_clear_placeholder_url(ph, language="en") with self.login_user_context(admin_user): response = self.client.post(endpoint, {"test": 0}) self.assertEqual(response.status_code, 200) # After cleaning the de placeholder, en placeholder must still have all the plugins self.assertEqual(ph.get_plugins("en").count(), 0) def test_empty_placeholder_in_correct_language(self): """ Test that Cleaning a placeholder only affect current language contents """ # create some objects page_en = create_page("EmptyPlaceholderTestPage (EN)", "nav_playground.html", "en") ph = page_en.get_placeholders("en").get(slot="body") # add the text plugin to the en version of the page add_plugin(ph, "TextPlugin", "en", body="Hello World EN 1") add_plugin(ph, "TextPlugin", "en", body="Hello World EN 2") # creating a de title of the page and adding plugins to it create_page_content("de", page_en.get_title(), page_en, slug=page_en.get_slug("en")) add_plugin(ph, "TextPlugin", "de", body="Hello World DE") add_plugin(ph, "TextPlugin", "de", body="Hello World DE 2") add_plugin(ph, "TextPlugin", "de", body="Hello World DE 3") # before cleaning the de placeholder self.assertEqual(ph.get_plugins("en").count(), 2) self.assertEqual(ph.get_plugins("de").count(), 3) admin_user, staff = self._get_guys() endpoint = self.get_clear_placeholder_url(ph, language="de") with self.login_user_context(admin_user): response = self.client.post(endpoint, {"test": 0}) self.assertEqual(response.status_code, 200) # After cleaning the de placeholder, en placeholder must still have all the plugins self.assertEqual(ph.get_plugins("en").count(), 2) self.assertEqual(ph.get_plugins("de").count(), 0) def test_template_inheritance_magic_with_three_levels_of_inheritance_inherits_from_parent(self): admin_user = self.get_superuser() grandparent_page = create_page("grandparent-page", "nav_playground.html", "en", created_by=admin_user) parent_page = create_page("parent-page", "col_two.html", "en", created_by=admin_user, parent=grandparent_page) child_page = create_page("child-page", "nav_playground.html", "en", created_by=admin_user, parent=parent_page) with self.login_user_context(admin_user): self.client.post( self.get_page_change_template_uri("en", child_page), {"template": TEMPLATE_INHERITANCE_MAGIC} ) child_page_content = PageContent.objects.get(page=child_page, language="en") self.assertEqual(child_page_content.get_template(), "col_two.html") def test_template_inheritance_magic_with_three_levels_of_inheritance_inherits_from_grandparent(self): admin_user = self.get_superuser() grandparent_page = create_page("grandparent-page", "nav_playground.html", "en", created_by=admin_user) parent_page = create_page( "parent-page", TEMPLATE_INHERITANCE_MAGIC, "en", created_by=admin_user, parent=grandparent_page ) child_page = create_page("child-page", "col_two.html", "en", created_by=admin_user, parent=parent_page) with self.login_user_context(admin_user): self.client.post( self.get_page_change_template_uri("en", child_page), {"template": TEMPLATE_INHERITANCE_MAGIC} ) child_page_content = PageContent.objects.get(page=child_page, language="en") self.assertEqual(child_page_content.get_template(), "nav_playground.html") @override_settings(CMS_TEMPLATES=[]) def test_placeholder_slot_inheritance_magic_with_two_levels_of_inheritance_without_configured_templates(self): admin_user = self.get_superuser() parent_page = create_page("grandparent-page", TEMPLATE_INHERITANCE_MAGIC, "en", created_by=admin_user) child_page = create_page( "parent-page", TEMPLATE_INHERITANCE_MAGIC, "en", created_by=admin_user, parent=parent_page ) child_slots = child_page.get_content_obj("en").get_placeholder_slots() self.assertEqual(child_slots, ("content",)) class AdminTests(AdminTestsBase): # TODO: needs tests for actual permissions, not only superuser/normaluser def setUp(self): self.page = create_page("testpage", "nav_playground.html", "en") def get_admin(self): User = get_user_model() fields = dict(email="admin@django-cms.org", is_staff=True, is_superuser=True) if User.USERNAME_FIELD != "email": fields[User.USERNAME_FIELD] = "admin" usr = User(**fields) usr.set_password(getattr(usr, User.USERNAME_FIELD)) usr.save() return usr def get_permless(self): User = get_user_model() fields = dict(email="permless@django-cms.org", is_staff=True) if User.USERNAME_FIELD != "email": fields[User.USERNAME_FIELD] = "permless" usr = User(**fields) usr.set_password(getattr(usr, User.USERNAME_FIELD)) usr.save() return usr def get_page(self): return self.page def test_admin_index(self): endpoint = admin_reverse("index") endpoint_page = admin_reverse("cms_page_changelist") endpoint_page_content = admin_reverse("cms_pagecontent_changelist") admin_user = self.get_admin() with self.login_user_context(admin_user): response = self.client.get(endpoint) self.assertEqual(response.status_code, 200) self.assertNotContains(response, endpoint_page) self.assertContains(response, endpoint_page_content) def test_change_innavigation(self): page = self.get_page() content = self.get_pagecontent_obj(page, "en") permless = self.get_permless() admin_user = self.get_admin() pagecontent_admin = self.pagecontent_admin_class with self.login_user_context(permless): request = self.get_request() response = pagecontent_admin.change_innavigation(request, content.pk) self.assertEqual(response.status_code, 405) with self.login_user_context(permless): request = self.get_request(post_data={"no": "data"}) response = pagecontent_admin.change_innavigation(request, content.pk) self.assertEqual(response.status_code, 403) with self.login_user_context(permless): request = self.get_request(post_data={"no": "data"}) self.assertEqual(response.status_code, 403) with self.login_user_context(admin_user): request = self.get_request(post_data={"no": "data"}) self.assertRaises(Http404, pagecontent_admin.change_innavigation, request, content.pk + 100) with self.login_user_context(permless): request = self.get_request(post_data={"no": "data"}) response = pagecontent_admin.change_innavigation(request, content.pk) self.assertEqual(response.status_code, 403) with self.login_user_context(admin_user): request = self.get_request(post_data={"no": "data"}) old = page.get_in_navigation() response = pagecontent_admin.change_innavigation(request, content.pk) self.assertEqual(response.status_code, 204) page = self.reload(page) self.assertEqual(old, not page.get_in_navigation()) def test_remove_plugin_requires_post(self): ph = self.page.get_placeholders("en")[0] plugin = add_plugin(ph, "TextPlugin", "en", body="test") admin_user = self.get_admin() with self.login_user_context(admin_user): endpoint = self.get_delete_plugin_uri(plugin) response = self.client.get(endpoint) self.assertEqual(response.status_code, 200) def test_too_many_plugins_global(self): conf = { "body": { "limits": { "global": 1, }, }, } admin_user = self.get_admin() url = admin_reverse("cms_placeholder_add_plugin") with self.settings(CMS_PERMISSION=False, CMS_PLACEHOLDER_CONF=conf): page = create_page("somepage", "nav_playground.html", "en") body = page.get_placeholders("en").get(slot="body") add_plugin(body, "TextPlugin", "en", body="text") with self.login_user_context(admin_user): data = { "plugin_type": "TextPlugin", "placeholder_id": body.pk, "target_language": "en", } response = self.client.post(url, data) self.assertEqual(response.status_code, HttpResponseBadRequest.status_code) def test_too_many_plugins_type(self): conf = { "body": { "limits": { "TextPlugin": 1, }, }, } admin_user = self.get_admin() url = admin_reverse("cms_placeholder_add_plugin") with self.settings(CMS_PERMISSION=False, CMS_PLACEHOLDER_CONF=conf): page = create_page("somepage", "nav_playground.html", "en") body = page.get_placeholders("en").get(slot="body") add_plugin(body, "TextPlugin", "en", body="text") with self.login_user_context(admin_user): data = { "plugin_type": "TextPlugin", "placeholder_id": body.pk, "target_language": "en", "plugin_parent": "", } response = self.client.post(url, data) self.assertEqual(response.status_code, HttpResponseBadRequest.status_code) def test_page_edit_field_endpoint(self): endpoint = ( admin_reverse("cms_page_edit_title_fields", args=(self.page.pk, "en")) + "?language=en&edit_fields=page_title" ) with self.login_user_context(self.get_superuser()): response = self.client.get(endpoint) self.assertContains( response, '', ) class NoDBAdminTests(CMSTestCase): @property def admin_class(self): return site._registry[Page] def test_lookup_allowed_site__exact(self): request = self.get_request() self.assertTrue(self.admin_class.lookup_allowed("site__exact", "1", request=request)) def test_lookup_allowed_published(self): request = self.get_request() self.assertTrue(self.admin_class.lookup_allowed("site__exact", "1", request=request)) class PluginPermissionTests(AdminTestsBase): def setUp(self): self._page = create_page("test page", "nav_playground.html", "en") self._placeholder = self._page.get_placeholders("en")[0] def _get_admin(self): User = get_user_model() fields = dict(email="admin@django-cms.org", is_staff=True, is_active=True) if User.USERNAME_FIELD != "email": fields[User.USERNAME_FIELD] = "admin" admin_user = User(**fields) admin_user.set_password("admin") admin_user.save() return admin_user def _get_page_admin(self): return admin.site._registry[Page] def _give_permission(self, user, model, permission_type, save=True): codename = f"{permission_type}_{model._meta.object_name.lower()}" user.user_permissions.add(Permission.objects.get(codename=codename)) def _give_page_permission_rights(self, user): self._give_permission(user, PagePermission, "add") self._give_permission(user, PagePermission, "change") self._give_permission(user, PagePermission, "delete") def _get_change_page_request(self, user, page): return type("Request", (object,), {"user": user, "path": self.get_page_change_uri("en", page)}) def _give_cms_permissions(self, user, save=True): for perm_type in ["add", "change", "delete"]: for model in [Page, PageContent]: self._give_permission(user, model, perm_type, False) gpp = GlobalPagePermission.objects.create( user=user, can_change=True, can_delete=True, can_publish=True, can_change_advanced_settings=False, can_change_permissions=False, can_move_page=True, ) gpp.sites = Site.objects.all() if save: user.save() def _create_plugin(self): plugin = add_plugin(self._placeholder, "TextPlugin", "en") return plugin def test_plugin_edit_wrong_url(self): """User tries to edit a plugin using a random url. 404 response returned""" plugin = self._create_plugin() _, normal_guy = self._get_guys() if get_user_model().USERNAME_FIELD == "email": self.client.login(username="test@test.com", password="test@test.com") else: self.client.login(username="test", password="test") self._give_permission(normal_guy, Text, "change") endpoint = "{}edit-plugin/{}/".format( admin_reverse("cms_placeholder_edit_plugin", args=[plugin.id]), plugin.id ) endpoint += "?cms_path=/en/" response = self.client.post(endpoint, dict()) self.assertEqual(response.status_code, HttpResponseNotFound.status_code) self.assertTrue("Page not found" in force_str(response.content)) class AdminFormsTests(AdminTestsBase): def test_clean_overwrite_url(self): """ A manual path needs to be stripped from leading and trailing slashes. """ superuser = self.get_superuser() cms_page = create_page("test page", "nav_playground.html", "en") page_data = { "title": "test page", "slug": "test-page", "overwrite_url": "/overwrite/url/", "template": cms_page.get_template("en"), } endpoint = self.get_page_change_uri("en", cms_page) with self.login_user_context(superuser): response = self.client.post(endpoint, page_data) self.assertRedirects(response, self.get_pages_admin_list_uri("en")) self.assertSequenceEqual( cms_page.urls.values_list("path", "managed"), [("overwrite/url", False)], ) def test_missmatching_site_parent_dotsite(self): superuser = self.get_superuser() new_site = Site.objects.create(id=2, domain="foo.com", name="foo.com") parent_page = api.create_page("test", get_cms_setting("TEMPLATES")[0][0], "fr", site=new_site) new_page_data = { "title": "Title", "slug": "slug", "parent_page": parent_page.pk, } with self.login_user_context(superuser): # Invalid parent endpoint = self.get_page_add_uri("en") response = self.client.post(endpoint, new_page_data) expected_error = ( '

" ) self.assertEqual(response.status_code, 200) self.assertContains(response, expected_error, html=True) def test_form_errors(self): superuser = self.get_superuser() site0 = Site.objects.create(id=2, domain="foo.com", name="foo.com") page1 = api.create_page("test", get_cms_setting("TEMPLATES")[0][0], "fr", site=site0) new_page_data = { "title": "Title", "slug": "home", "parent_page": page1.pk, } endpoint = self.get_page_add_uri("en") with self.login_user_context(superuser): # Invalid parent response = self.client.post(endpoint, new_page_data) expected_error = ( '" ) self.assertEqual(response.status_code, 200) self.assertContains(response, expected_error, html=True) new_page_data = { "title": "Title", "slug": "#", } with self.subTest("Invalid slug"): with self.login_user_context(superuser): # Invalid slug response = self.client.post(endpoint, new_page_data) expected_error = ( '" ) self.assertEqual(response.status_code, 200) self.assertContains(response, expected_error, html=True) page2 = api.create_page("test", get_cms_setting("TEMPLATES")[0][0], "en") new_page_data = { "title": "Title", "slug": "test", } with self.login_user_context(superuser): with self.subTest("Duplicate slug / path"): response = self.client.post(endpoint, new_page_data) expected_error = ( '" ).format(self.get_page_change_uri("en", page2)) self.assertEqual(response.status_code, 200) self.assertContains(response, expected_error, html=True) @override_settings(CMS_PERMISSION=False) def test_reverse_id_error_location(self): superuser = self.get_superuser() create_page("Page 1", "nav_playground.html", "en", reverse_id="p1") page2 = create_page("Page 2", "nav_playground.html", "en") page2_endpoint = self.get_admin_url(Page, "advanced", page2.pk) # Assemble a bunch of data to test the page form page2_data = { "reverse_id": "p1", "template": "col_two.html", } with self.login_user_context(superuser): response = self.client.post(page2_endpoint, page2_data) expected_error = '" self.assertEqual(response.status_code, 200) self.assertContains(response, expected_error.format(page2.pk), html=True) @override_settings(CMS_PERMISSION=False) def test_advanced_settings_endpoint_fails_gracefully(self): admin_user = self.get_superuser() page = create_page("Page 1", "nav_playground.html", "en") page_data = { "language": "en", "template": "col_two.html", } path = admin_reverse("cms_page_advanced", args=(page.pk,)) # It's important to test fields that are validated # automatically by Django vs fields that are validated # via the clean() method by us. # Fields validated by Django will not be in cleaned data # if they have an error so if we rely on these in the clean() # method then an error will be raised. # So test that the form short circuits if there's errors. page_data["application_urls"] = "TestApp" with self.login_user_context(admin_user): response = self.client.post(path, page_data) # Assert user is not redirected because there was a form error self.assertEqual(response.status_code, 200) page = page.reload() # Make sure no change was made self.assertEqual(page.application_urls, None) @override_settings(CMS_PERMISSION=True) def test_advanced_settings_endpoint_permissions(self): """ Test that the advanced settings endpoint respects various permission levels """ admin_user = self.get_superuser() staff_user = self._get_staff_user(use_global_permissions=False) page = create_page("Page 1", "nav_playground.html", "en", created_by=admin_user) path = admin_reverse("cms_page_advanced", args=(page.pk,)) # Test with no permissions with self.login_user_context(staff_user): response = self.client.get(path) self.assertEqual(response.status_code, 403) # Test with change permission only (no advanced settings permission) gpp = GlobalPagePermission.objects.create( user=staff_user, can_change=True, can_change_advanced_settings=False, ) gpp.sites.set(Site.objects.all()) with self.login_user_context(staff_user): response = self.client.get(path) self.assertEqual(response.status_code, 403) # Test with advanced settings permission only gpp.can_change = False gpp.can_change_advanced_settings = True gpp.save() with self.login_user_context(staff_user): response = self.client.get(path) self.assertEqual(response.status_code, 403) # Test with both permissions gpp.can_change = True gpp.can_change_advanced_settings = True gpp.save() with self.login_user_context(staff_user): response = self.client.get(path) # Check that advanced settings fields are present self.assertContains(response, 'name="reverse_id"') self.assertContains(response, 'name="application_urls"') # Test with permissions change permission only gpp.can_change_advanced_settings = False gpp.can_change_permissions = True gpp.save() # Ensure no advanced settings fields are shown without proper permissions with self.login_user_context(staff_user): response = self.client.get(path) self.assertNotContains(response, 'name="reverse_id"') self.assertNotContains(response, 'name="application_urls"') def test_advanced_settings_toolbar_entry(self): """ Test that the advanced settings toolbar entry is only shown to users with appropriate permissions and offers the correct content """ admin_user = self.get_superuser() staff_user = self._get_staff_user(use_global_permissions=False) page = create_page("Test Page", "nav_playground.html", "en", created_by=admin_user) page_url = get_object_edit_url(page.get_admin_content("en")) advanced_settings_url = admin_reverse("cms_page_advanced", args=(page.pk,)) snippet = """
  • Advanced settings...
  • """ disabled_snippet = snippet.format("cms-toolbar-item-navigation-disabled", 'tabindex="-1" ', advanced_settings_url) enabled_snippet = snippet.format("", "", advanced_settings_url) # Test with admin user - should see advanced settings with self.login_user_context(admin_user): response = self.client.get(page_url) self.assertEqual(response.status_code, 200) # Check for advanced settings in toolbar self.assertContains(response, enabled_snippet, html=True) # Test with staff user with no permissions with self.login_user_context(staff_user): response = self.client.get(page_url) # Should not contain advanced settings link self.assertContains(response, disabled_snippet, html=True) # Test with change permission but no advanced settings permission gpp = GlobalPagePermission.objects.create( user=staff_user, can_change_permissions=True, can_change_advanced_settings=False, ) gpp.sites.set(Site.objects.all()) with self.login_user_context(staff_user): response = self.client.get(page_url) self.assertContains(response, enabled_snippet, html=True) # Test with permissions change permissions only gpp.can_change_permissions = False gpp.can_change_advanced_settings = True gpp.save() with self.login_user_context(staff_user): response = self.client.get(page_url) self.assertContains(response, enabled_snippet, html=True) def test_advanced_settings_returns_404(self): invalid_page_pk = 0 path = admin_reverse("cms_page_advanced", args=(invalid_page_pk,)) with self.login_user_context(self.get_superuser()): response = self.client.get(path) self.assertEqual(response.status_code, 404) def test_render_edit_mode(self): from django.core.cache import cache cache.clear() homepage = create_page("Test", "static.html", "en") homepage.set_as_homepage() for placeholder in homepage.get_placeholders("en"): add_plugin(placeholder, TextPlugin, "en", body="Test") user = self.get_superuser() self.assertEqual(homepage.get_placeholders("en").count(), 2) with self.login_user_context(user): output = force_str(self.client.get("/en/").content) self.assertIn("Test", output) for placeholder in homepage.get_placeholders("en"): add_plugin(placeholder, TextPlugin, "en", body="Test") output = force_str(self.client.get("/en/").content) self.assertIn("Test", output) def test_tree_view_queries(self): from django.core.cache import cache cache.clear() for i in range(10): create_page("Test%s" % i, "col_two.html", "en") for placeholder in Placeholder.objects.all(): add_plugin(placeholder, TextPlugin, "en", body="Test") user = self.get_superuser() with self.login_user_context(user): with self.assertNumQueries(8): force_str(self.client.get(self.get_pages_admin_list_uri("en"))) def test_smart_link_pages(self): admin, staff_guy = self._get_guys() page_url = URL_CMS_PAGE_PUBLISHED # Not sure how to achieve this with reverse... create_page("home", "col_two.html", "en") with self.login_user_context(staff_guy): multi_title_page = create_page( "main_title", "col_two.html", "en", overwrite_url="overwritten_url", menu_title="menu_title" ) title = multi_title_page.get_content_obj() title.page_title = "page_title" title.save() multi_title_page.save() # Non ajax call should return a 403 as this page shouldn't be accessed by anything else but ajax queries self.assertEqual(403, self.client.get(page_url).status_code) self.assertEqual(200, self.client.get(page_url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").status_code) # Test that the query param is working as expected. self.assertEqual( 1, len( json.loads( self.client.get( page_url, {"q": "main_title"}, HTTP_X_REQUESTED_WITH="XMLHttpRequest" ).content.decode("utf-8") ) ), ) self.assertEqual( 1, len( json.loads( self.client.get( page_url, {"q": "menu_title"}, HTTP_X_REQUESTED_WITH="XMLHttpRequest" ).content.decode("utf-8") ) ), ) self.assertEqual( 1, len( json.loads( self.client.get( page_url, {"q": "overwritten_url"}, HTTP_X_REQUESTED_WITH="XMLHttpRequest" ).content.decode("utf-8") ) ), ) self.assertEqual( 1, len( json.loads( self.client.get( page_url, {"q": "page_title"}, HTTP_X_REQUESTED_WITH="XMLHttpRequest" ).content.decode("utf-8") ) ), ) class PagePropsMovedToPageContentTests(CMSTestCase): def test_moved_fields(self): non_editables = [ "id", "changed_by", "changed_date", "created_by", "creation_date", "page_id", "in_navigation", "language", ] change_page_form_fieldsets = flatten_fieldsets(ChangePageForm.fieldsets) page_content_fields = [field.attname for field in PageContent._meta.fields] # filter the non editables from PageContent fields filtered_page_content_fields = list(set(page_content_fields) - set(non_editables)) for field in filtered_page_content_fields: self.assertIn(field, change_page_form_fieldsets) class AdminPageEditContentSizeTests(AdminTestsBase): """ System user count influences the size of the page edit page, but the users are only 2 times present on the page The test relates to extra=0 at PagePermissionInlineAdminForm and ViewRestrictionInlineAdmin """ def test_editpage_contentsize(self): """ Expected a username only 2 times in the content, but a relationship between usercount and pagesize """ with self.settings(CMS_PERMISSION=True): admin_user = self.get_superuser() PAGE_NAME = "TestPage" USER_NAME = "test_size_user_0" current_site = Site.objects.get(pk=1) page = create_page(PAGE_NAME, "nav_playground.html", "en", site=current_site, created_by=admin_user) page.save() self._page = page with self.login_user_context(admin_user): url = base.URL_CMS_PAGE_ADVANCED_CHANGE % self._page.pk response = self.client.get(url) self.assertEqual(response.status_code, 200) old_response_size = len(response.content) old_user_count = get_user_model().objects.count() # create additional user and reload the page get_user_model().objects.create_user( username=USER_NAME, email=USER_NAME + "@django-cms.org", password=USER_NAME ) user_count = get_user_model().objects.count() more_users_in_db = old_user_count < user_count # we have more users self.assertTrue(more_users_in_db, "New users got NOT created") response = self.client.get(url) new_response_size = len(response.content) page_size_grown = old_response_size < new_response_size # expect that the pagesize gets influenced by the useramount of the system self.assertTrue(page_size_grown, "Page size has not grown after user creation") # usernames are only 2 times in content text = smart_str(response.content, response.charset) foundcount = text.count(USER_NAME) # 2 forms contain usernames as options self.assertEqual( foundcount, 2, f"Username {USER_NAME} appeared {foundcount} times in response.content, expected 2 times", ) class AdminPageTreeTests(AdminTestsBase): def test_move_node(self): admin_user, staff = self._get_guys() page_admin = self.page_admin_class alpha = create_page("Alpha", "nav_playground.html", "en") beta = create_page("Beta", TEMPLATE_INHERITANCE_MAGIC, "en") gamma = create_page("Gamma", TEMPLATE_INHERITANCE_MAGIC, "en") delta = create_page("Delta", TEMPLATE_INHERITANCE_MAGIC, "en") # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Beta to be a child of Alpha data = { "id": beta.pk, "position": 0, "target": alpha.pk, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=beta.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Gamma to be a child of Beta data = { "id": gamma.pk, "position": 0, "target": beta.pk, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=gamma.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 2) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Delta to be a child of Beta data = { "id": delta.pk, "position": 0, "target": gamma.pk, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=delta.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 3) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 2) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Beta to the root as node #1 (positions are 0-indexed) data = { "id": beta.pk, "position": 1, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=beta.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 0) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 2) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Beta to be a child of Alpha again data = { "id": beta.pk, "position": 0, "target": alpha.pk, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=beta.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 3) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 2) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Gamma to the root as node #1 (positions are 0-indexed) data = { "id": gamma.pk, "position": 1, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=gamma.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 1) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 0) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 1) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Gamma # ⊢ Delta # Move Delta to the root as node #1 (positions are 0-indexed) data = { "id": delta.pk, "position": 1, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=delta.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 1) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 0) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 0) # Current structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Delta # ⊢ Gamma # Move Gamma to be a child of Delta data = { "id": gamma.pk, "position": 1, "target": delta.pk, } with self.login_user_context(admin_user): request = self.get_request(post_data=data) response = page_admin.move_page(request, page_id=gamma.pk) data = json.loads(response.content.decode("utf8")) self.assertEqual(response.status_code, 200) self.assertEqual(data["status"], 200) alpha.refresh_from_db() self.assertEqual(alpha.get_descendants().count(), 1) beta.refresh_from_db() self.assertEqual(beta.get_descendants().count(), 0) gamma.refresh_from_db() self.assertEqual(gamma.get_descendants().count(), 0) delta.refresh_from_db() self.assertEqual(delta.get_descendants().count(), 1) # Final structure: # # ⊢ Alpha # ⊢ Beta # ⊢ Delta # ⊢ Gamma def test_create_page_language(self): """tests if the New Page button creates a page content object in the language specified by the language selectors. The creates pages in all languages and checks if the "+" button creates a child in the same language""" admin_user, staff = self._get_guys() pagecontent_admin = self.pagecontent_admin_class languages = get_language_list(site_id=settings.SITE_ID) # Run through all languages url = admin_reverse("cms_pagecontent_changelist") add_url = admin_reverse("cms_pagecontent_add") # "Add page" button self.assertIn("/en/", add_url + "?language=en") # English admin (default in tests) with self.login_user_context(admin_user): request = self.get_request(url) response = pagecontent_admin.changelist_view(request) self.assertContains(response, f"{add_url}?language=en") for language in languages: # Now check all language with the languages selector defined request = self.get_request(path=f"{url}?language={language}") # Language of the page tree response = pagecontent_admin.changelist_view(request) self.assertContains(response, f'href="{add_url}?language={language}&site=1"') # Create pages in all languages page = {} for language in languages: page[language] = create_page("Alpha", "nav_playground.html", language) # Get the page tree and see if the href triggers an add page content for the # selected language url = admin_reverse("cms_pagecontent_get_tree") for language in languages: request = self.get_request(path=f"{url}?language={language}") response = pagecontent_admin.get_tree(request) self.assertContains(response, f'href="{add_url}?parent_page={page[language].id}&language={language}"') class AdminInputSanitationTests(AdminTestsBase): @property def settings_admin_class(self): return site._registry[UserSettings] def test_admin_session_store(self): """ Settings added to admin through session store should be escaped """ admin_user, staff = self._get_guys() with self.login_user_context(admin_user): request = self.get_request( self.settings_admin_class.urls[0], post_data={ "settings": '', }, ) response = self.settings_admin_class.session_store(request) self.assertEqual(response.content, b'"<script>alert("hello world")</script>"')