From 13276208cda0e4b323788214305b3122cca4dc01 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Tue, 28 Oct 2025 10:02:28 +0100 Subject: [PATCH 1/4] fix: Create alias view errored --- .gitignore | 1 + djangocms_alias/cms_plugins.py | 32 ++++++++++++++------------------ djangocms_alias/models.py | 31 +++++++++++++++---------------- djangocms_alias/views.py | 4 ++-- 4 files changed, 32 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 55a062bc..76e29a7c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .idea/ .tox/ .eggs/ +.vscode/ dist/ !djangocms_alias/static/djangocms_alias/js/dist/ build/ diff --git a/djangocms_alias/cms_plugins.py b/djangocms_alias/cms_plugins.py index 4bc764a2..630903b2 100644 --- a/djangocms_alias/cms_plugins.py +++ b/djangocms_alias/cms_plugins.py @@ -1,5 +1,3 @@ -from copy import copy - from cms.plugin_base import CMSPluginBase, PluginMenuItem from cms.plugin_pool import plugin_pool from cms.toolbar.utils import get_object_edit_url @@ -140,26 +138,24 @@ def can_detach(cls, user, target_placeholder, plugins): @classmethod def detach_alias_plugin(cls, plugin, language): - source_placeholder = plugin.alias.get_placeholder(language, show_draft_content=True) # We're in edit mode + source_plugins = plugin.alias.get_plugins(language, show_draft_content=True) # We're in edit mode target_placeholder = plugin.placeholder + plugin_position = plugin.position + plugin_parent = plugin.parent + target_placeholder.delete_plugin(plugin) + if source_plugins: + if target_last_plugin := target_placeholder.get_last_plugin(plugin.language): + target_placeholder._shift_plugin_positions( + language, + start=plugin_position, + offset=len(source_plugins) + target_last_plugin.position + 1, # enough space to shift back + ) - # Deleting uses a copy of a plugin to preserve pk on existing - # ``plugin`` object. This is done due to - # plugin.get_plugin_toolbar_info requiring a PK in a passed - # instance. - target_placeholder.delete_plugin(copy(plugin)) - target_placeholder._shift_plugin_positions( - language, - plugin.position, - offset=target_placeholder.get_last_plugin_position(language), - ) - if source_placeholder: - source_plugins = source_placeholder.get_plugins_list() - copied_plugins = copy_plugins_to_placeholder( + return copy_plugins_to_placeholder( source_plugins, placeholder=target_placeholder, language=language, - start_positions={language: plugin.position}, + root_plugin=plugin_parent, + start_positions={language: plugin_position}, ) - return copied_plugins return [] diff --git a/djangocms_alias/models.py b/djangocms_alias/models.py index 3c99cdec..9df35f04 100644 --- a/djangocms_alias/models.py +++ b/djangocms_alias/models.py @@ -193,13 +193,13 @@ def get_placeholder(self, language=None, show_draft_content=False): content = self.get_content(language=language, show_draft_content=show_draft_content) return getattr(content, "placeholder", None) - def get_plugins(self, language=None): + def get_plugins(self, language=None, show_draft_content=False): if not language: language = get_language() try: return self._plugins_cache[language] except KeyError: - placeholder = self.get_placeholder(language) + placeholder = self.get_placeholder(language, show_draft_content=show_draft_content) plugins = placeholder.get_plugins_list() if placeholder else [] self._plugins_cache[language] = plugins return self._plugins_cache[language] @@ -307,25 +307,27 @@ def populate(self, replaced_placeholder=None, replaced_plugin=None, plugins=None placeholder=self.placeholder, ) return - if replaced_placeholder: - plugins = replaced_placeholder.get_plugins(self.language) - placeholder = replaced_placeholder - add_plugin_kwargs = {} - else: - plugins = CMSPlugin.objects.filter( - id__in=[replaced_plugin.pk] + replaced_plugin._get_descendants_ids(), + replaced_placeholder.cmsplugin_set.update(placeholder=self.placeholder) + return add_plugin( + replaced_placeholder, + plugin_type="Alias", + language=self.language, + alias=self.alias, ) - placeholder = replaced_plugin.placeholder - add_plugin_kwargs = {"position": "left", "target": replaced_plugin} + + placeholder = replaced_plugin.placeholder + plugins = CMSPlugin.objects.filter( + id__in=[replaced_plugin.pk] + replaced_plugin._get_descendants_ids(), + ) + add_plugin_kwargs = {"position": "left", "target": replaced_plugin} copy_plugins_to_placeholder( plugins, placeholder=self.placeholder, language=self.language, ) - plugins.delete() - placeholder._recalculate_plugin_positions(self.language) + replaced_plugin.delete() new_plugin = add_plugin( placeholder, @@ -334,9 +336,6 @@ def populate(self, replaced_placeholder=None, replaced_plugin=None, plugins=None alias=self.alias, **add_plugin_kwargs, ) - if replaced_plugin: - new_plugin.position = replaced_plugin.position - new_plugin.save(update_fields=["position"]) return new_plugin diff --git a/djangocms_alias/views.py b/djangocms_alias/views.py index 1ade7d2f..c4ae42bf 100644 --- a/djangocms_alias/views.py +++ b/djangocms_alias/views.py @@ -144,13 +144,13 @@ def create_alias_view(request): emit_content_change([alias_content]) if replace: - plugin = create_form.cleaned_data.get("plugin") + create_form.cleaned_data.get("plugin") placeholder = create_form.cleaned_data.get("placeholder") return render_replace_response( request, new_plugins=[alias_plugin], source_placeholder=placeholder, - source_plugin=plugin, + # source_plugin=plugin, ) return HttpResponse(JAVASCRIPT_SUCCESS_RESPONSE) From cbcb310b05fd54fc87dbfdafac9a7465a0dc68a5 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Tue, 28 Oct 2025 10:13:11 +0100 Subject: [PATCH 2/4] fix: tests --- djangocms_alias/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/djangocms_alias/views.py b/djangocms_alias/views.py index c4ae42bf..6d707a69 100644 --- a/djangocms_alias/views.py +++ b/djangocms_alias/views.py @@ -144,13 +144,13 @@ def create_alias_view(request): emit_content_change([alias_content]) if replace: - create_form.cleaned_data.get("plugin") + plugin = create_form.cleaned_data.get("plugin") placeholder = create_form.cleaned_data.get("placeholder") return render_replace_response( request, new_plugins=[alias_plugin], source_placeholder=placeholder, - # source_plugin=plugin, + source_plugin=plugin, ) return HttpResponse(JAVASCRIPT_SUCCESS_RESPONSE) @@ -183,7 +183,7 @@ def render_replace_response(request, new_plugins, source_placeholder=None, sourc "moved_plugins": move_plugins, "is_popup": True, } - if source_plugin is not None: + if source_plugin is not None and source_plugin.pk: context["replaced_plugin"] = json.dumps( get_plugin_toolbar_info(source_plugin), ) From 345045808587c8145b4faa4749b5a06d05b8a729 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Tue, 28 Oct 2025 20:59:36 +0100 Subject: [PATCH 3/4] fix: Plugins cache --- djangocms_alias/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/djangocms_alias/models.py b/djangocms_alias/models.py index 9df35f04..6a7f172c 100644 --- a/djangocms_alias/models.py +++ b/djangocms_alias/models.py @@ -196,13 +196,14 @@ def get_placeholder(self, language=None, show_draft_content=False): def get_plugins(self, language=None, show_draft_content=False): if not language: language = get_language() + cache_key = f"{language}-{show_draft_content}" try: - return self._plugins_cache[language] + return self._plugins_cache[cache_key] except KeyError: placeholder = self.get_placeholder(language, show_draft_content=show_draft_content) plugins = placeholder.get_plugins_list() if placeholder else [] - self._plugins_cache[language] = plugins - return self._plugins_cache[language] + self._plugins_cache[cache_key] = plugins + return self._plugins_cache[cache_key] def get_languages(self): if not self._content_languages_cache: From 33c5aa58642564034f2ef140b2a33abd7df733b8 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Wed, 29 Oct 2025 12:50:04 +0100 Subject: [PATCH 4/4] fix: Improve databridge interface --- djangocms_alias/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/djangocms_alias/views.py b/djangocms_alias/views.py index 6d707a69..a12aa818 100644 --- a/djangocms_alias/views.py +++ b/djangocms_alias/views.py @@ -136,6 +136,8 @@ def create_alias_view(request): "Plugins are required to create an alias", ) + plugin = create_form.cleaned_data.get("plugin") + plugin_pk = plugin.pk if plugin else None replace = create_form.cleaned_data.get("replace") if not Alias.can_create_alias(user, plugins, replace): raise PermissionDenied @@ -144,8 +146,9 @@ def create_alias_view(request): emit_content_change([alias_content]) if replace: - plugin = create_form.cleaned_data.get("plugin") placeholder = create_form.cleaned_data.get("placeholder") + if plugin is not None: + plugin.pk = plugin_pk # Restore pk after it was set to None in form.save() return render_replace_response( request, new_plugins=[alias_plugin], @@ -183,7 +186,7 @@ def render_replace_response(request, new_plugins, source_placeholder=None, sourc "moved_plugins": move_plugins, "is_popup": True, } - if source_plugin is not None and source_plugin.pk: + if source_plugin is not None: context["replaced_plugin"] = json.dumps( get_plugin_toolbar_info(source_plugin), )