From 040fa7b14d9d857442727bd1bb6bdd11c9b14150 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 21 Nov 2023 16:28:43 +0100 Subject: [PATCH 1/3] Do not return section children in @search-filters endpoint if they are types omitted from search results --- CHANGES.rst | 3 +- .../policy/restapi/search_filters/get.py | 80 ++++++++++--------- .../policy/tests/test_search_filters_api.py | 29 +++++++ 3 files changed, 73 insertions(+), 39 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 3e9c243..126b0c5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 5.0.7 (unreleased) ------------------ -- Nothing changed yet. +- Do not return section children in @search-filters endpoint if they are types omitted from search results. + [cekk] 5.0.6 (2023-08-29) diff --git a/src/design/plone/policy/restapi/search_filters/get.py b/src/design/plone/policy/restapi/search_filters/get.py index d4185ab..c0cc5e1 100644 --- a/src/design/plone/policy/restapi/search_filters/get.py +++ b/src/design/plone/policy/restapi/search_filters/get.py @@ -6,6 +6,7 @@ from plone.restapi.interfaces import ISerializeToJsonSummary from plone.restapi.services import Service from Products.CMFPlone.interfaces import ISearchSchema +from Products.CMFCore.utils import getToolByName from zope.component import getMultiAdapter from zope.component import getUtility from zope.i18n import translate @@ -37,47 +38,50 @@ def get_portal_types(self): return sorted(types, key=lambda k: k["label"]) def reply(self): - settings = api.portal.get_registry_record( - "search_sections", - interface=IDesignPloneSettings, + settings = ( + api.portal.get_registry_record( + "search_sections", + interface=IDesignPloneSettings, + ) + or "[]" ) + utils = getToolByName(self.context, "plone_utils") + sections = [] - if settings: - settings = json.loads(settings) - for setting in settings: - items = [] - for section_settings in setting.get("items") or []: - for uid in section_settings.get("linkUrl") or []: - try: - section = api.content.get(UID=uid) - except Unauthorized: - # private folder - continue - if section: - item_infos = getMultiAdapter( - (section, self.request), - ISerializeToJsonSummary, - )() - children = section.listFolderContents() - if children: - item_infos["items"] = [] - for children in section.listFolderContents(): - item_infos["items"].append( - getMultiAdapter( - (children, self.request), - ISerializeToJsonSummary, - )() - ) - if section_settings.get("title", ""): - item_infos["title"] = section_settings["title"] - items.append(item_infos) - if items: - sections.append( - { - "rootPath": setting.get("rootPath", ""), - "items": items, - } + for setting in json.loads(settings): + items = [] + for section_settings in setting.get("items") or []: + for uid in section_settings.get("linkUrl") or []: + try: + section = api.content.get(UID=uid) + except Unauthorized: + # private folder + continue + if not section: + continue + item_infos = getMultiAdapter( + (section, self.request), + ISerializeToJsonSummary, + )() + children = section.listFolderContents( + contentFilter={"portal_type": utils.getUserFriendlyTypes()} ) + item_infos["items"] = [ + getMultiAdapter( + (x, self.request), + ISerializeToJsonSummary, + )() + for x in children + ] + item_infos["title"] = section_settings.get("title", "") + items.append(item_infos) + if items: + sections.append( + { + "rootPath": setting.get("rootPath", ""), + "items": items, + } + ) topics = [ getMultiAdapter( (brain, self.request), diff --git a/src/design/plone/policy/tests/test_search_filters_api.py b/src/design/plone/policy/tests/test_search_filters_api.py index 11084ad..6cc4b67 100644 --- a/src/design/plone/policy/tests/test_search_filters_api.py +++ b/src/design/plone/policy/tests/test_search_filters_api.py @@ -97,3 +97,32 @@ def test_endpoint_return_list_of_searchable_types(self): self.assertIn("portal_types", response) types = [x["id"] for x in response["portal_types"]] self.assertNotIn("Document", types) + + def test_endpoint_do_not_return_contents_that_are_not_searchable(self): + api.content.create( + container=self.portal["amministrazione"], + type="UnitaOrganizzativa", + title="UO Foo", + id="uo-foo", + ) + commit() + + response = self.api_session.get("/@search-filters").json() + amministrazione = response["sections"][0]["items"][0] + + self.assertEqual("Amministrazione", amministrazione["title"]) + self.assertEqual(8, len(amministrazione["items"])) + self.assertEqual("UO Foo", amministrazione["items"][-1]["title"]) + + registry = getUtility(IRegistry) + settings = registry.forInterface(ISearchSchema, prefix="plone") + settings.types_not_searched = tuple( + list(settings.types_not_searched) + ["UnitaOrganizzativa"] + ) + commit() + + response = self.api_session.get("/@search-filters").json() + amministrazione = response["sections"][0]["items"][0] + + self.assertEqual("Amministrazione", amministrazione["title"]) + self.assertEqual(7, len(amministrazione["items"])) From 090a1c809582368d208832375fe9216c5356b6ca Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 21 Nov 2023 16:30:26 +0100 Subject: [PATCH 2/3] Do not return section children in @search-filters endpoint if they are types omitted from search results --- src/design/plone/policy/restapi/search_filters/get.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/design/plone/policy/restapi/search_filters/get.py b/src/design/plone/policy/restapi/search_filters/get.py index c0cc5e1..ecb7756 100644 --- a/src/design/plone/policy/restapi/search_filters/get.py +++ b/src/design/plone/policy/restapi/search_filters/get.py @@ -38,12 +38,8 @@ def get_portal_types(self): return sorted(types, key=lambda k: k["label"]) def reply(self): - settings = ( - api.portal.get_registry_record( - "search_sections", - interface=IDesignPloneSettings, - ) - or "[]" + settings = api.portal.get_registry_record( + "search_sections", interface=IDesignPloneSettings, default="[]" ) utils = getToolByName(self.context, "plone_utils") From 93d172c0949b9d5920892301cf1c963dcb5e95b7 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Thu, 23 Nov 2023 17:29:08 +0100 Subject: [PATCH 3/3] better handle empty value Co-authored-by: Mauro Amico --- src/design/plone/policy/restapi/search_filters/get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design/plone/policy/restapi/search_filters/get.py b/src/design/plone/policy/restapi/search_filters/get.py index ecb7756..6b8f0d8 100644 --- a/src/design/plone/policy/restapi/search_filters/get.py +++ b/src/design/plone/policy/restapi/search_filters/get.py @@ -44,7 +44,7 @@ def reply(self): utils = getToolByName(self.context, "plone_utils") sections = [] - for setting in json.loads(settings): + for setting in json.loads(settings or "[]"): items = [] for section_settings in setting.get("items") or []: for uid in section_settings.get("linkUrl") or []: