From 1ff76b1dc45173b8bcfb7f85f9f95d95fa4d8fd3 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 1 Dec 2025 14:52:34 +0100 Subject: [PATCH 1/3] feat: Provide non-editable placeholders with new draft option --- djangocms_versioning/helpers.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/djangocms_versioning/helpers.py b/djangocms_versioning/helpers.py index bad4e108..6fa4b689 100644 --- a/djangocms_versioning/helpers.py +++ b/djangocms_versioning/helpers.py @@ -17,8 +17,9 @@ from django.db import models from django.http import HttpRequest from django.template.loader import render_to_string +from django.urls import reverse from django.utils.encoding import force_str -from django.utils.translation import get_language +from django.utils.translation import get_language, gettext as _ from . import versionables from .conf import EMAIL_NOTIFICATIONS_FAIL_SILENTLY @@ -243,12 +244,21 @@ def is_content_editable(placeholder: Placeholder, user: models.Model) -> bool: :return: Boolean """ try: - versionables.for_content(placeholder.source) + proxy_model = versionables.for_content(placeholder.source).version_model_proxy except KeyError: return True from .models import Version version = Version.objects.get_for_content(placeholder.source) + if version.state == DRAFT: + return True + if version.check_edit_redirect.as_bool(user): + placeholder.new_draft = _("Create new draft to edit") + placeholder.new_draft_method = "cms-form-post-method" + placeholder.new_draft_url = reverse( + f"admin:{proxy_model._meta.app_label}_{proxy_model.__name__.lower()}_edit_redirect", + args=(version.pk,), + ) return version.state == DRAFT From 3c3a6dc621f5964fa692af9ec3665a3f26804d81 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 1 Dec 2025 14:55:36 +0100 Subject: [PATCH 2/3] add tests --- tests/test_checks.py | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/test_checks.py b/tests/test_checks.py index 2f067ead..7557ebb7 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -49,3 +49,63 @@ def test_check_unversioned_model(self): class CheckInjectTestCase(CMSTestCase): def test_draft_state_check_is_injected_into_default_checks(self): self.assertIn(is_content_editable, PlaceholderRelationField.default_checks) + + +class NewDraftPropertiesTestCase(CMSTestCase): + def test_new_draft_properties_set_for_published_placeholder(self): + """Test that new_draft properties are set on published placeholders""" + user = self.get_superuser() + version = PageVersionFactory(state=PUBLISHED) + placeholder = PlaceholderFactory(source=version.content) + + # Call is_content_editable which should set the new_draft properties + is_content_editable(placeholder, user) + + # Check that new_draft properties are set + self.assertTrue(hasattr(placeholder, "new_draft")) + self.assertTrue(hasattr(placeholder, "new_draft_method")) + self.assertTrue(hasattr(placeholder, "new_draft_url")) + self.assertEqual(placeholder.new_draft_method, "cms-form-post-method") + self.assertIn("edit-redirect", placeholder.new_draft_url) + + def test_new_draft_properties_not_set_for_archived_placeholder(self): + """Test that new_draft properties are NOT set on archived placeholders""" + user = self.get_superuser() + version = PageVersionFactory(state=ARCHIVED) + placeholder = PlaceholderFactory(source=version.content) + + # Call is_content_editable which should NOT set the new_draft properties for archived + is_content_editable(placeholder, user) + + # Check that new_draft properties are NOT set + self.assertFalse(hasattr(placeholder, "new_draft")) + self.assertFalse(hasattr(placeholder, "new_draft_method")) + self.assertFalse(hasattr(placeholder, "new_draft_url")) + + def test_new_draft_properties_not_set_for_unpublished_placeholder(self): + """Test that new_draft properties are NOT set on unpublished placeholders""" + user = self.get_superuser() + version = PageVersionFactory(state=UNPUBLISHED) + placeholder = PlaceholderFactory(source=version.content) + + # Call is_content_editable which should NOT set the new_draft properties for unpublished + is_content_editable(placeholder, user) + + # Check that new_draft properties are NOT set + self.assertFalse(hasattr(placeholder, "new_draft")) + self.assertFalse(hasattr(placeholder, "new_draft_method")) + self.assertFalse(hasattr(placeholder, "new_draft_url")) + + def test_new_draft_properties_not_set_for_draft_placeholder(self): + """Test that new_draft properties are NOT set on draft placeholders (already editable)""" + user = self.get_superuser() + version = PageVersionFactory(state=DRAFT) + placeholder = PlaceholderFactory(source=version.content) + + # Call is_content_editable which should NOT set the new_draft properties for drafts + is_content_editable(placeholder, user) + + # Check that new_draft properties are NOT set (draft is already editable) + self.assertFalse(hasattr(placeholder, "new_draft")) + self.assertFalse(hasattr(placeholder, "new_draft_method")) + self.assertFalse(hasattr(placeholder, "new_draft_url")) From cb6c88a53b182d75bbf8856674f44c9ffadbd219 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 1 Dec 2025 15:04:00 +0100 Subject: [PATCH 3/3] Update djangocms_versioning/helpers.py Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- djangocms_versioning/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djangocms_versioning/helpers.py b/djangocms_versioning/helpers.py index 6fa4b689..64a10e89 100644 --- a/djangocms_versioning/helpers.py +++ b/djangocms_versioning/helpers.py @@ -256,7 +256,7 @@ def is_content_editable(placeholder: Placeholder, user: models.Model) -> bool: placeholder.new_draft = _("Create new draft to edit") placeholder.new_draft_method = "cms-form-post-method" placeholder.new_draft_url = reverse( - f"admin:{proxy_model._meta.app_label}_{proxy_model.__name__.lower()}_edit_redirect", + f"admin:{proxy_model._meta.app_label}_{proxy_model._meta.model_name}_edit_redirect", args=(version.pk,), ) return version.state == DRAFT