From df6a0d02e8f98b9a64b850f0b4b80031f6f5be37 Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Mon, 3 May 2021 13:32:13 -0500 Subject: [PATCH 1/7] allow related items to be hidden if unpublished --- castle/cms/browser/viewlets/configure.zcml | 10 +++++++ castle/cms/browser/viewlets/relateditems.py | 31 +++++++++++++++++++++ castle/cms/interfaces/controlpanel.py | 8 ++++++ castle/cms/profiles/3_0_00/registry.xml | 12 ++++++++ 4 files changed, 61 insertions(+) create mode 100644 castle/cms/browser/viewlets/relateditems.py create mode 100644 castle/cms/profiles/3_0_00/registry.xml diff --git a/castle/cms/browser/viewlets/configure.zcml b/castle/cms/browser/viewlets/configure.zcml index 1c6bc84c4..ad5779463 100644 --- a/castle/cms/browser/viewlets/configure.zcml +++ b/castle/cms/browser/viewlets/configure.zcml @@ -23,6 +23,16 @@ layer="castle.cms.interfaces.ICastleLayer" template="social_tags_body.pt" /> + + + diff --git a/castle/cms/browser/viewlets/relateditems.py b/castle/cms/browser/viewlets/relateditems.py new file mode 100644 index 000000000..98e8d14f1 --- /dev/null +++ b/castle/cms/browser/viewlets/relateditems.py @@ -0,0 +1,31 @@ +from plone.app.layout.viewlets.content import ContentRelatedItems as BaseContentRelatedItems +from Products.CMFCore.utils import getToolByName +from plone import api + + +class ContentRelatedItems(BaseContentRelatedItems): + + # override this method to respect castle.display_unpublished_related_items registry setting + def related2brains(self, related): + catalog = getToolByName(self.context, "portal_catalog") + brains = [] + for r in related: + path = r.to_path + if path is None: + # Item was deleted. The related item should have been cleaned + # up, but apparently this does not happen. + continue + # the query will return an empty list if the user + # has no permission to see the target object + catalog_args = { + 'path': dict(query=path, depth=0), + } + if not api.portal.get_registry_record( + 'plone.display_unpublished_related_items', + default=False, + ): + catalog_args['review_state'] = 'published' + brains.extend( + catalog(**catalog_args) + ) + return brains diff --git a/castle/cms/interfaces/controlpanel.py b/castle/cms/interfaces/controlpanel.py index 577468e8f..42caefda7 100644 --- a/castle/cms/interfaces/controlpanel.py +++ b/castle/cms/interfaces/controlpanel.py @@ -213,6 +213,14 @@ class ISecuritySchema(controlpanel.ISecuritySchema): default=False, required=False) + display_unpublished_related_items = schema.Bool( + title=u'Display unpublished related items', + description=u'Check this box to allow Related Items that are not currently published ' + u'to be displayed when viewing content containing related items.', + default=False, + required=False, + ) + class IAnnouncementData(Interface): show_announcement = schema.Bool( diff --git a/castle/cms/profiles/3_0_00/registry.xml b/castle/cms/profiles/3_0_00/registry.xml new file mode 100644 index 000000000..a1a4d3190 --- /dev/null +++ b/castle/cms/profiles/3_0_00/registry.xml @@ -0,0 +1,12 @@ + + + + + False + + From 589e94dacaf3c46ff10febfd2e6faf404207283b Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Mon, 3 May 2021 13:32:45 -0500 Subject: [PATCH 2/7] upgrade step --- castle/cms/profiles/3_0_00/metadata.xml | 4 ++++ castle/cms/profiles/default/metadata.xml | 2 +- castle/cms/upgrades.zcml | 22 ++++++++++++++++++++-- castle/cms/upgrades/__init__.py | 2 ++ 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 castle/cms/profiles/3_0_00/metadata.xml diff --git a/castle/cms/profiles/3_0_00/metadata.xml b/castle/cms/profiles/3_0_00/metadata.xml new file mode 100644 index 000000000..b6bd42a67 --- /dev/null +++ b/castle/cms/profiles/3_0_00/metadata.xml @@ -0,0 +1,4 @@ + + + 3000 + diff --git a/castle/cms/profiles/default/metadata.xml b/castle/cms/profiles/default/metadata.xml index 7ed429eb5..326afc723 100644 --- a/castle/cms/profiles/default/metadata.xml +++ b/castle/cms/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 2631 + 3000 profile-plone.app.querystring:default profile-plone.app.mosaic:default diff --git a/castle/cms/upgrades.zcml b/castle/cms/upgrades.zcml index 55f0d135d..e28f1731c 100644 --- a/castle/cms/upgrades.zcml +++ b/castle/cms/upgrades.zcml @@ -441,7 +441,7 @@ + + + + + diff --git a/castle/cms/upgrades/__init__.py b/castle/cms/upgrades/__init__.py index 2abd75e2b..9a41edf97 100644 --- a/castle/cms/upgrades/__init__.py +++ b/castle/cms/upgrades/__init__.py @@ -68,3 +68,5 @@ def upgrade(context, logger=None): upgrade_2_6_27 = default_upgrade_factory('2_6_27') upgrade_2_6_30 = default_upgrade_factory('2_6_30') upgrade_2_6_31 = default_upgrade_factory('2_6_31') + +upgrade_3_0_00 = default_upgrade_factory('3_0_00') From 9c16eee20c291302021fabc830aa3d064604b16d Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Mon, 3 May 2021 13:33:17 -0500 Subject: [PATCH 3/7] documentation --- HISTORY.rst | 3 ++- docs/controlpanel.rst | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index bd9fc5822..fd2c9bca3 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,7 +4,8 @@ Changelog 3.0.0b1 (unreleased) -------------------- -- Nothing changed yet. +- Implement functionality to hide related resource from being displayed for + unpublished content 3.0.0b0 (2021-04-30) diff --git a/docs/controlpanel.rst b/docs/controlpanel.rst index 8383bb2c5..37ceee54b 100644 --- a/docs/controlpanel.rst +++ b/docs/controlpanel.rst @@ -135,4 +135,13 @@ The can be configured on the environment with these environment settings: - `GOOGLE_CLIENT_SECRET` (you can also provide twitter auth key and secret through control panel; however, -in the future, these will all be environment variables) \ No newline at end of file +in the future, these will all be environment variables) + + +Security Settings +----------------- + +in /@@security-controlpanel, you can change settings for the way some content shows +up. For example, `Allow access to published objects inside private containers` and +`Display unpublished related items` settings can be changed there. (Both of these +values default to False) From 99724da9a8f13a1ede082bcee37cfa3ba1e289cb Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Mon, 3 May 2021 13:37:09 -0500 Subject: [PATCH 4/7] flake8 --- castle/cms/browser/viewlets/relateditems.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/castle/cms/browser/viewlets/relateditems.py b/castle/cms/browser/viewlets/relateditems.py index 98e8d14f1..90361d792 100644 --- a/castle/cms/browser/viewlets/relateditems.py +++ b/castle/cms/browser/viewlets/relateditems.py @@ -18,7 +18,7 @@ def related2brains(self, related): # the query will return an empty list if the user # has no permission to see the target object catalog_args = { - 'path': dict(query=path, depth=0), + 'path': dict(query=path, depth=0), } if not api.portal.get_registry_record( 'plone.display_unpublished_related_items', From a52a02eb7584b3bd5ca23bea1f000642feed0013 Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Mon, 3 May 2021 16:58:43 -0500 Subject: [PATCH 5/7] add test for new related resource functionality --- castle/cms/tests/test_related_resources.py | 99 ++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 castle/cms/tests/test_related_resources.py diff --git a/castle/cms/tests/test_related_resources.py b/castle/cms/tests/test_related_resources.py new file mode 100644 index 000000000..d726834f1 --- /dev/null +++ b/castle/cms/tests/test_related_resources.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +import unittest + +from castle.cms.testing import CASTLE_PLONE_INTEGRATION_TESTING +from plone import api +from plone.app.testing import TEST_USER_ID +from plone.app.testing import TEST_USER_NAME +from plone.app.testing import login +from plone.app.testing import setRoles +from zope.component import getUtility +from zope.intid.interfaces import IIntIds +from z3c.relationfield import RelationValue +from castle.cms.browser.viewlets.relateditems import ContentRelatedItems + + +class TestRelatedResources(unittest.TestCase): + + layer = CASTLE_PLONE_INTEGRATION_TESTING + + def setUp(self): + self.portal = self.layer['portal'] + self.request = self.layer['request'] + self.intid_utility = getUtility(IIntIds) + + login(self.portal, TEST_USER_NAME) + setRoles(self.portal, TEST_USER_ID, ('Member', 'Manager')) + self.source_document = self.create_document('source') + + def create_document(self, id): + return api.content.create( + type='Document', + id=id, + container=self.portal, + ) + + @property + def related_items(self): + content_related_items = ContentRelatedItems( + context=self.source_document, + request=self.source_document.REQUEST, + view=self.source_document.view, + ) + return [ + brain.getObject() + for brain in content_related_items.related_items() + ] + + def set_up_target_documents(self): + target_documents = [ + self.create_document('target_1'), + self.create_document('target_2'), + ] + self.source_document.relatedItems = [ + RelationValue(self.intid_utility.getId(target)) + for target in target_documents + ] + self.assertEqual( + len(self.source_document.relatedItems), + 2, + ) + return target_documents + + def assertContentRelatedItemsLength(self, asserted_length): + self.assertEqual( + len(self.related_items), + asserted_length, + ) + + def test_display_unpublished_related_items_false_by_default(self): + display_unpublished_related_items = api.portal.get_registry_record( + 'plone.display_unpublished_related_items', + default=True, + ) + self.assertFalse(display_unpublished_related_items) + + def test_content_related_items_override_when_display_unpublished_false(self): + target_documents = self.set_up_target_documents() + self.assertEqual(len(self.related_items), 0) + for expected_related_items_count, target_document in enumerate(target_documents, start=1): + self.assertFalse(target_document in self.related_items) + api.content.transition( + obj=target_document, + to_state='published', + ) + self.assertEqual( + len(self.related_items), + expected_related_items_count, + ) + self.assertTrue(target_document in self.related_items) + + def test_content_related_items_override_when_display_unpublished_true(self): + target_documents = self.set_up_target_documents() + api.portal.set_registry_record( + 'plone.display_unpublished_related_items', + True, + ) + self.assertEqual(len(self.related_items), 2) + for target_document in target_documents: + self.assertTrue(target_document in self.related_items) From 225217bacc478cdd106034f95085f0f2dd4a315b Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Tue, 4 May 2021 10:59:50 -0500 Subject: [PATCH 6/7] small testing change --- castle/cms/tests/test_related_resources.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/castle/cms/tests/test_related_resources.py b/castle/cms/tests/test_related_resources.py index d726834f1..3aa1743b6 100644 --- a/castle/cms/tests/test_related_resources.py +++ b/castle/cms/tests/test_related_resources.py @@ -33,6 +33,12 @@ def create_document(self, id): container=self.portal, ) + def publish(self, item): + api.content.transition( + obj=item, + to_state='published', + ) + @property def related_items(self): content_related_items = ContentRelatedItems( @@ -75,13 +81,14 @@ def test_display_unpublished_related_items_false_by_default(self): def test_content_related_items_override_when_display_unpublished_false(self): target_documents = self.set_up_target_documents() + api.portal.set_registry_record( + 'plone.display_unpublished_related_items', + False, + ) self.assertEqual(len(self.related_items), 0) for expected_related_items_count, target_document in enumerate(target_documents, start=1): self.assertFalse(target_document in self.related_items) - api.content.transition( - obj=target_document, - to_state='published', - ) + self.publish(target_document) self.assertEqual( len(self.related_items), expected_related_items_count, From 0e709fa16b0ef195a74ff648826a480dffc76362 Mon Sep 17 00:00:00 2001 From: Brian Duncan Date: Tue, 4 May 2021 11:00:55 -0500 Subject: [PATCH 7/7] flake8 --- castle/cms/tests/test_related_resources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/castle/cms/tests/test_related_resources.py b/castle/cms/tests/test_related_resources.py index 3aa1743b6..6727ad4ce 100644 --- a/castle/cms/tests/test_related_resources.py +++ b/castle/cms/tests/test_related_resources.py @@ -38,7 +38,7 @@ def publish(self, item): obj=item, to_state='published', ) - + @property def related_items(self): content_related_items = ContentRelatedItems(