10000 fix: Menus crashed when unexpected page content was present by fsbraun · Pull Request #8052 · django-cms/django-cms · GitHub
[go: up one dir, main page]

Skip to content

fix: Menus crashed when unexpected page content was present #8052

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 15 commits into from
Nov 4, 2024
Merged
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
django-5.1.txt,
]
os: [
ubuntu-20.04,
ubuntu-latest,
]
exclude:
- requirements-file: django-5.0.txt
Expand Down Expand Up @@ -225,7 +225,7 @@ jobs:

services:
postgres:
image: postgres:15
image: postgres:17
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand Down
14 changes: 1 addition & 13 deletions cms/admin/pageadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,18 +813,6 @@ def log_change(self, request, object, message):
# Block the admin log for change. A signal takes care of this!
return

def get_object(self, request, object_id, from_field=None):
"""
Return an instance matching the field and value provided, the primary
key is used if no field is provided. Return ``None`` if no match is
found or the object_id fails validation.
"""
obj = super().get_object(request, object_id, from_field)

if obj:
obj.page.admin_content_cache[obj.language] = obj
return obj

def get_admin_url(self, action, *args):
url_name = f"{self.opts.app_label}_{self.opts.model_name}_{action}"
return admin_reverse(url_name, args=args)
Expand Down Expand Up @@ -1402,7 +1390,7 @@ def get_tree(self, request):
Prefetch(
'pagecontent_set',
to_attr='filtered_translations',
queryset=PageContent.admin_manager.get_queryset(),
queryset=PageContent.admin_manager.get_queryset().latest_content(),
),
)
rows = self.get_tree_rows(
Expand Down
2 changes: 1 addition & 1 deletion cms/cms_menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def get_menu_node_for_page(renderer, page, language, fallbacks=None, endpoint=Fa
for lang in [language] + fallbacks:
translation = page.page_content_cache.get(lang)

if translation:
if translation and lang in page.urls_cache:
page_url = page.urls_cache[lang]
# Do we have a redirectURL?
attr["redirect_url"] = translation.redirect # save redirect URL if any
Expand Down
2 changes: 1 addition & 1 deletion cms/models/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def subordinate_to_user(self, user, site):
from cms.models import PermissionTuple
allow_list = Q()
for perm_tuple in get_change_permissions_perm_tuples(user, site, check_global=False):
allow_list |= PermissionTuple(perm_tuple).allow_list("page__node")
allow_list |= PermissionTuple(perm_tuple).allow_list("page__node")

# get permission set, but without objects targeting user, or any group
# in which he can be
Expand Down
2 changes: 1 addition & 1 deletion cms/models/pagemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from cms.utils import i18n
from cms.utils.compat.warnings import RemovedInDjangoCMS43Warning
from cms.utils.conf import get_cms_setting
from cms.utils.i18n import get_current_language, get_fallback_languages
from cms.utils.i18n import get_current_language
from cms.utils.page import get_clean_username
from menus.menu_pool import menu_pool

Expand Down
2 changes: 1 addition & 1 deletion cms/models/permissionmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def contains(self, path: str, steplen: int = TreeNode.steplen) -> bool:
return False

def allow_list(self, filter: str = "", steplen: int = TreeNode.steplen) -> Q:
if filter !="":
if filter != "":
filter = f"{filter}__"
grant_on, path = self
if grant_on == ACCESS_PAGE:
Expand Down
1 change: 0 additions & 1 deletion cms/plugin_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,6 @@ def _get_cached_placeholder_content(self, placeholder, language):
language_cache[placeholder.pk] = cached_value
return language_cache.get(placeholder.pk)


def _get_content_object(self, page, slots=None):
if self.toolbar.get_object() == page:
# Current object belongs to the page itself
Expand Down
12 changes: 6 additions & 6 deletions cms/templates/cms/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h2>

<section class="cms-welcome-cards">
<div class="cms-welcome-section">
{% blocktranslate %}
{% blocktrans %}
<h2>Help Funding</h2>
<p>
Your funding directly benefits the product, mainly through the
Expand All @@ -50,10 +50,10 @@ <h2>Help Funding</h2>
A quick way for yourself or your organisation to donate is on
<a href="https://github.com/sponsors/django-cms">Github Sponsors</a>.
</p>
{% endblocktranslate %}
{% endblocktrans %}
</div>
<div class="cms-welcome-section">
{% blocktranslate %}
{% blocktrans %}
<h2>Join Us</h2>
<p>
The django CMS Association is a non-profit organisation that funds and steers the development of
Expand All @@ -63,10 +63,10 @@ <h2>Join Us</h2>
You can <a href="https://www.django-cms.org/en/memberships/">join both as an individual or as an
organisation</a>.
</p>
{% endblocktranslate %}
{% endblocktrans %}
</div>
<div class="cms-welcome-section">
{% blocktranslate %}
{% blocktrans %}
<h2>Contribute</h2>
<ul>
<li><a href="https://www.django-cms.org/en/contribute/">Contribute code:</a> fix a bug or
Expand All @@ -76,7 +76,7 @@ <h2>Contribute</h2>
<li><a href="https://www.django-cms.org/en/repositories-plugins/">Open-source your work:</a>
Make the ecosystem strong.</li>
</ul>
{% endblocktranslate %}
{% endblocktrans %}
</div>
</section>

Expand Down
1 change: 1 addition & 0 deletions cms/templatetags/cms_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ def boolean_icon(value):
mapped_icon,
)


@register.tag(name="page_submit_row")
class PageSubmitRow(InclusionTag):
name = 'page_submit_row'
Expand Down
2 changes: 2 additions & 0 deletions cms/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ def test_smart_link_pages(self):
))
)


class PagePropsMovedToPageContentTests(CMSTestCase):

def test_moved_fields(self):
Expand All @@ -823,6 +824,7 @@ def test_moved_fields(self):
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,
Expand Down
3 changes: 2 additions & 1 deletion cms/tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
from cms.test_utils.testcases import CMSTestCase
from cms.toolbar_pool import toolbar_pool
from cms.utils.compat.warnings import RemovedInDjangoCMS42Warning, RemovedInDjangoCMS43Warning
from cms.utils.compat.warnings import RemovedInDjangoCMS43Warning
from cms.utils.urlutils import admin_reverse


Expand Down Expand Up @@ -427,6 +427,7 @@ def test_deprecated_title_extension(self):

class SampleExtensionToolbar2(ExtensionToolbar):
model = MyPageContentExtension

def populate(self):
nonlocal urls
urls = self.get_title_extension_admin()
Expand Down
7 changes: 1 addition & 6 deletions cms/tests/test_i18n.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from collections import deque
from importlib import import_module
from unittest.mock import patch

Expand All @@ -7,11 +6,6 @@
from django.test.utils import override_settings

from cms import api
from cms.plugin_rendering import (
ContentRenderer,
LegacyRenderer,
StructureRenderer,
)
from cms.test_utils.testcases import CMSTestCase
from cms.utils import get_language_from_request, i18n
from cms.utils.compat import DJANGO_2_2
Expand Down Expand Up @@ -519,6 +513,7 @@ def test_redirect_on_fallback(self):
response_en = self.client.get(page.get_absolute_url(language="en"))
self.assertRedirects(response_en, page.get_absolute_url(language="fr"))


@override_settings(
LANGUAGE_CODE='en',
LANGUAGES=(('fr', 'French'),
Expand Down
1 change: 0 additions & 1 deletion cms/tests/test_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ def test_delete_orphaned_plugins(self):
max_positon = placeholder.cmsplugin_set.aggregate(models.Max('position'))['position__max']
self.assertEqual(max_positon, 3)


def test_uninstall_plugins_without_plugin(self):
out = StringIO()
management.call_command('cms', 'uninstall', 'plugins', PLUGIN, interactive=False, stdout=out)
Expand Down
3 changes: 1 addition & 2 deletions cms/tests/test_page_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1604,6 +1604,7 @@ def test_add_page_no_redirect(self):
self.assertRedirects(response, redirect_url)
self.assertEqual(Page.objects.all().count(), 2)


class PermissionsTestCase(PageTestBase):
def assertContainsPermissions(self, response):
try:
Expand Down Expand Up @@ -2695,7 +2696,6 @@ def test_permission_cache_invalidation_on_group_add(self):

self.assertIsNone(get_permission_cache(staff_user, "change_page"))


def test_permission_cache_invalidation_on_group_remove(self):
"""
Permissions cache is invalidated if the group relationship of a user is changed
Expand All @@ -2714,7 +2714,6 @@ def test_permission_cache_invalidation_on_group_remove(self):

self.assertIsNone(get_permission_cache(staff_user, "change_page"))


def test_user_can_copy_page(self):
"""
Test that a page can be copied via the admin
Expand Down
1 change: 0 additions & 1 deletion cms/tests/test_permmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ def test_default_plugins(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(CMSPlugin.objects.count(), 1)


def test_super_can_add_plugin(self):
self._add_plugin(self.user_super, page=self.slave_page)

Expand Down
14 changes: 9 additions & 5 deletions cms/tests/test_placeholder.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,14 +761,14 @@ def test_plugins_prepopulate(self):

conf = {
'col_left': {
'default_plugins' : [
'default_plugins': [
{
'plugin_type':'TextPlugin',
'values':{'body':'<p>en default body 1</p>'},
'plugin_type': 'TextPlugin',
'values': {'body': '<p>en default body 1</p>'},
},
{
'plugin_type':'TextPlugin',
'values':{'body':'<p>en default body 2</p>'},
'plugin_type': 'TextPlugin',
'values': {'body': '<p>en default body 2</p>'},
},
]
},
Expand Down Expand Up @@ -1376,6 +1376,10 @@ def test_delete(self):
.values_list('pk', flat=True)
)

new_tree = self.get_plugins().values_list('pk', 'position')
expected = [(pk, pos) for pos, pk in enumerate(plugin_tree_all, 1)]
self.assertSequenceEqual(new_tree, expected)

for plugin in self.get_plugins().filter(parent__isnull=True):
for plugin_id in [plugin.pk] + tree[plugin.pk]:
plugin_tree_all.remove(plugin_id)
Expand Down
2 changes: 1 addition & 1 deletion cms/tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
)
from cms.test_utils.testcases import CMSTestCase
from cms.toolbar.toolbar import CMSToolbar
from cms.toolbar.utils import get_object_edit_url, get_toolbar_from_request
from cms.toolbar.utils import get_object_edit_url
from cms.utils.plugins import copy_plugins_to_placeholder, get_plugins


Expand Down
1 change: 0 additions & 1 deletion cms/tests/test_templatetags.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def test_get_preview_url(self):
self.assertIn("/en", page_preview_url)
self.assertIn("/de/", german_content_preview_url)


def test_get_admin_tree_title(self):
page = create_page("page_a", "nav_playground.html", "en")
self.assertEqual(get_page_display_name(page), 'page_a')
Expand Down
4 changes: 2 additions & 2 deletions cms/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from django.urls import clear_url_caches, reverse
from django.utils.translation import override as force_language

from cms import api
from cms.api import create_page, create_page_content
from cms.middleware.toolbar import ToolbarMiddleware
from cms.models import PageContent, PagePermission, Placeholder, UserSettings
Expand Down Expand Up @@ -432,6 +431,7 @@ def test_context_current_page(self):
template = Variable('CMS_TEMPLATE').resolve(response.context)
self.assertEqual(template, page_template)


class EndpointTests(CMSTestCase):

def setUp(self) -> None:
Expand Down Expand Up @@ -463,7 +463,7 @@ def test_render_object_structure_i18n(self):
self._add_plugin_to_placeholder(placeholder, "TextPlugin", language="fr")
with force_language("fr"):
setting, _ = UserSettings.objects.get_or_create(user=self.get_superuser())
setting.language="fr"
setting.language = "fr"
setting.save()
structure_endpoint_url = admin_reverse(
"cms_placeholder_render_object_structure",
Expand Down
4 changes: 2 additions & 2 deletions cms/toolbar/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
)

from cms.constants import PLACEHOLDER_TOOLBAR_JS, PLUGIN_TOOLBAR_JS
from cms.models import PageContent
from cms.utils import get_language_list
from cms.utils.conf import get_cms_setting
from cms.utils.urlutils import admin_reverse
Expand Down Expand Up @@ -170,7 +169,7 @@ def get_object_edit_url(obj: models.Model, language: str = None) -> str:
return url


def get_object_preview_url(obj:models.Model, language: str = None) -> str:
def get_object_preview_url(obj: models.Model, language: str = None) -> str:
"""
Returns the url of the preview endpoint for the given object. The object must be frontend-editable
and registered as such with cms.
Expand Down Expand Up @@ -207,6 +206,7 @@ def get_object_structure_url(obj: models.Model, language: str = None) -> str:
with force_language(language):
return admin_reverse('cms_placeholder_render_object_structure', args=[content_type.pk, obj.pk])


def get_object_for_language(obj: models.Model, language: str, latest: bool = False) -> Optional[models.Model]:
"""
Retrieves t F544 he correct content object for the target language. The object must be frontend-editable
Expand Down
2 changes: 1 addition & 1 deletion cms/utils/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from cms.constants import ROOT_USER_LEVEL, SCRIPT_USERNAME
from cms.exceptions import NoPermissionsException
from cms.models import GlobalPagePermission, Page, PagePermission
from cms.models import GlobalPagePermission, PagePermission
from cms.utils.compat.dj import available_attrs
from cms.utils.conf import get_cms_setting
from cms.utils.page import get_clean_username
Expand Down
1 change: 0 additions & 1 deletion cms/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ def details(request, slug):
# Get a Page model object from the request
site = get_current_site()
page = get_page_from_request(request, use_path=slug)
toolbar = get_toolbar_from_request(request)
tree_nodes = TreeNode.objects.get_for_site(site)

if not page and not slug and not tree_nodes.exists():
Expand Down
Loading
0