8000 fix: Page Content Extension toolbar by fsbraun · Pull Request #7708 · django-cms/django-cms · GitHub
[go: up one dir, main page]

Skip to content

fix: Page Content Extension toolbar #7708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 72 additions & 39 deletions cms/extensions/toolbar.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
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
from cms.utils.urlutils import admin_reverse


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):
"""
Expand All @@ -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):
Expand All @@ -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
40 changes: 31 additions & 9 deletions cms/tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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
Expand Down
0