diff --git a/cms/extensions/toolbar.py b/cms/extensions/toolbar.py index 62deb766052..b43f12f8d51 100644 --- a/cms/extensions/toolbar.py +++ b/cms/extensions/toolbar.py @@ -1,5 +1,8 @@ +import warnings + from django.urls import NoReverseMatch +from cms.models import PageContent from cms.toolbar_base import CMSToolbar from cms.utils import get_language_list from cms.utils.page_permissions import user_can_change_page @@ -7,8 +10,11 @@ class ExtensionToolbar(CMSToolbar): + """Offers simplified API for providing the user access to the admin of page extensions and + page content extensions through the toolbar.""" model = None page = None + page_content = None def _setup_extension_toolbar(self): """ @@ -22,12 +28,18 @@ def _setup_extension_toolbar(self): page = self._get_page() if page and user_can_change_page(self.request.user, page=page): - return self.toolbar.get_or_create_menu('page') + return self.toolbar.get_or_create_menu("page") return def _get_page(self): if not self.page: - self.page = self.request.current_page + obj = self.toolbar.get_object() # Try getting the PageContent object from the toolbar + if isinstance(obj, PageContent): + self.page = obj.page + self.page_content = obj + else: + self.page = self.request.current_page # Otherwise get Page object from the request + self.page_content = self.page.get_content_obj(self.current_lang) return self.page def get_page_extension_admin(self): @@ -45,60 +57,81 @@ def get_page_extension_admin(self): except self.model.DoesNotExist: page_extension = None try: - model_name = self.model.__name__.lower() + app_label, model_name = self.model._meta.app_label, self.model.__name__.lower() if page_extension: - admin_url = admin_reverse( - '%s_%s_change' % (self.model._meta.app_label, model_name), - args=(page_extension.pk,)) + admin_url = admin_reverse(f"{app_label}_{model_name}_change", args=(page_extension.pk,)) else: - admin_url = "%s?extended_object=%s" % ( - admin_reverse('%s_%s_add' % (self.model._meta.app_label, model_name)), - self.page.pk) + admin_url = "{}?extended_object={}".format( + admin_reverse(f"{app_label}_{model_name}_add"), self.page.pk + ) except NoReverseMatch: # pragma: no cover admin_url = None return page_extension, admin_url def get_title_extension_admin(self, language=None): """ - Get the admin urls for the title extensions menu items, depending on whether a TitleExtension instance exists - for each PageContent in the current page. - A single language can be passed to only work on a single title. + Deprecated. - Return a list of tuples of the title extension and the url; the extension is None if no instance exists, - the url is None is no admin is registered for the extension. + Reflects now obsolete behavior in django CMS 3.x: + + Get the admin urls for the page content extensions menu items, depending on whether a + :class:`~cms.extensions.models.PageContentExtension` instance exists for each + :class:`~cms.models.contentmodels.PageContent` in the current page. + A single language can be passed to only work on a single page content object. + + Return a list of tuples of the page content extension and the url; the extension is None + if no instance exists, the url is None is no admin is registered for the extension. """ + warnings.warn( + "get_title_extension_admin has been deprecated and replaced by get_page_content_extension_admin", + DeprecationWarning, + stacklevel=2, + ) page = self._get_page() + + page_contents = ( + page.pagecontent_set(manager="admin_manager") + .latest_content() + .filter(language__in=get_language_list(page.node.site_id)) + ) urls = [] - if language: - titles = page.get_content_obj(language), - else: - titles = page.pagecontent_set.filter(language__in=get_language_list(page.node.site_id)) - # Titles - for title in titles: - try: - title_extension = self.model.objects.get(extended_object_id=title.pk) - except self.model.DoesNotExist: - title_extension = None - try: - model_name = self.model.__name__.lower() - if title_extension: - admin_url = admin_reverse( - '%s_%s_change' % (self.model._meta.app_label, model_name), - args=(title_extension.pk,)) - else: - admin_url = "%s?extended_object=%s" % ( - admin_reverse('%s_%s_add' % (self.model._meta.app_label, model_name)), - title.pk) - except NoReverseMatch: # pragma: no cover - admin_url = None + + for page_content in page_contents: + admin_url = self.get_page_content_extension_admin(page_content) if admin_url: - urls.append((title_extension, admin_url)) + urls.append(admin_url) return urls + def get_page_content_extension_admin(self, page_content_obj=None): + """ + Get the admin url for the page content extensions menu item, depending on whether a + :class:`~cms.extensions.models.PageContentExtension` instance exists for the + :class:`~cms.models.contentmodels.PageContent` displayed. + + Return a tuple of the page content extension and the url; the extension is None + if no instance exists, the url is None is no admin is registered for the extension. + """ + self._get_page() + page_content = page_content_obj or self.page_content + try: + pagecontent_extension = self.model.objects.get(extended_object_id=page_content.pk) + except self.model.DoesNotExist: + pagecontent_extension = None + try: + app_label, model_name = self.model._meta.app_label, self.model.__name__.lower() + if pagecontent_extension: + admin_url = admin_reverse(f"{app_label}_{model_name}_change", args=(pagecontent_extension.pk,)) + else: + admin_url = "{}?extended_object={}".format( + admin_reverse(f"{app_label}_{model_name}_add"), page_content.pk + ) + except NoReverseMatch: # pragma: no cover + admin_url = None + return pagecontent_extension, admin_url + def _get_sub_menu(self, current_menu, key, label, position=None): """ Utility function to get a submenu of the current menu """ - extension_menu = current_menu.get_or_create_menu( - key, label, position=position) + extension_menu = current_menu.get_or_create_menu(key, label, position=position) return extension_menu diff --git a/cms/tests/test_extensions.py b/cms/tests/test_extensions.py index 121b02f9b9f..91def2d7c8b 100644 --- a/cms/tests/test_extensions.py +++ b/cms/tests/test_extensions.py @@ -397,7 +397,7 @@ def populate(self): self.assertIn("TestItem", response.rendered_content) toolbar_pool.toolbars = old_toolbars - def test_toolbar_title_extension(self): + def test_toolbar_page_content_extension(self): old_toolbars = deepcopy(toolbar_pool.toolbars) class SampleExtension(ExtensionToolbar): @@ -407,20 +407,42 @@ def populate(self): current_page_menu = self._setup_extension_toolbar() if current_page_menu: position = 0 - urls = self.get_title_extension_admin() - for title_extension, url in urls: - current_page_menu.add_modal_item( - 'TestItem', - url=url, - disabled=not self.toolbar.edit_mode_active, - position=position - ) + pagecontent_extension, url = self.get_page_content_extension_admin() + current_page_menu.add_modal_item( + 'TestItem', + url=url, + disabled=not self.toolbar.edit_mode_active, + position=position + ) toolbar_pool.register(SampleExtension) with self.login_user_context(self.admin): response = self.client.get('{}?edit'.format(self.page.get_absolute_url())) self.assertIn("TestItem", response.rendered_content) toolbar_pool.toolbars = old_toolbars + def test_deprecated_title_extension(self): + urls = [] + old_toolbars = deepcopy(toolbar_pool.toolbars) + + class SampleExtensionToolbar2(ExtensionToolbar): + model = MyPageContentExtension + def populate(self): + nonlocal urls + urls = self.get_title_extension_admin() + + toolbar_pool.register(SampleExtensionToolbar2) + + message = "get_title_extension_admin has been deprecated and replaced by get_page_content_extension_admin" + with self.login_user_context(self.admin): + self.assertWarns( + DeprecationWarning, + message, + lambda: self.client.get(self.page.get_absolute_url()), + ) + + self.assertEqual(len(urls), 2) + toolbar_pool.toolbars = old_toolbars + def test_admin_title_extension(self): with self.login_user_context(self.admin): # add a new extension