From fdc9ff8c87a99903f45c0dd6f3898f81bb5dcbe8 Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Mon, 27 Feb 2023 11:56:22 +0000 Subject: [PATCH 1/8] Don't carry out queue processing activities if the addon is not installed --- src/collective/elasticsearch/queueprocessor.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/collective/elasticsearch/queueprocessor.py b/src/collective/elasticsearch/queueprocessor.py index f0bffb2..e476ef0 100644 --- a/src/collective/elasticsearch/queueprocessor.py +++ b/src/collective/elasticsearch/queueprocessor.py @@ -89,6 +89,8 @@ def _uuid_path(self, obj): def index(self, obj, attributes=None): """Index the specified attributes for an obj.""" + if not self.manager.active: + return actions = self.actions uuid, path = self._uuid_path(obj) actions.uuid_path[uuid] = path @@ -122,10 +124,14 @@ def index(self, obj, attributes=None): def reindex(self, obj, attributes=None, update_metadata=False): """Reindex the specified attributes for an obj.""" + if not self.manager.active: + return self.index(obj, attributes) def unindex(self, obj): """Unindex the obj.""" + if not self.manager.active: + return actions = self.actions uuid, path = self._uuid_path(obj) actions.uuid_path[uuid] = path From 22d6e5f2b3966c2095abb17ddf30e79f2e7eb0e1 Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Wed, 1 Feb 2023 19:33:41 -0500 Subject: [PATCH 2/8] Add support for optional es host in worker via PLONE_ELASTICSEARCH_HOST env variable --- CHANGELOG.md | 2 ++ src/collective/elasticsearch/redis/tasks.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7fa5d..879f6f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - Handle negative term filters (fixes #101) @instification +- Add support for optional es host in worker via PLONE_ELASTICSEARCH_HOST env variable @maethu + ## 5.0.0 (2022-10-11) - Rename `master` branch to `main` @ericof diff --git a/src/collective/elasticsearch/redis/tasks.py b/src/collective/elasticsearch/redis/tasks.py index e71a2f6..74f28a6 100644 --- a/src/collective/elasticsearch/redis/tasks.py +++ b/src/collective/elasticsearch/redis/tasks.py @@ -54,6 +54,7 @@ def bulk_update(hosts, params, index_name, body): """ Collects all the data and updates elasticsearch """ + hosts = os.environ.get("PLONE_ELASTICSEARCH_HOST", hosts) connection = es_connection(hosts, **params) for item in body: @@ -81,6 +82,7 @@ def update_file_data(hosts, params, index_name, body): """ Get blob data from plone and index it via elasticsearch attachment pipeline """ + hosts = os.environ.get("PLONE_ELASTICSEARCH_HOST", hosts) connection = es_connection(hosts, **params) uuid, data = body From bf3d5731510e7ed7d9fdc1155f9a5a0e7a2ebad8 Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Thu, 2 Feb 2023 18:41:44 -0500 Subject: [PATCH 3/8] Use es_attributes instead of _es_attributes. _es_attributes might be not yet computed. --- src/collective/elasticsearch/queueprocessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collective/elasticsearch/queueprocessor.py b/src/collective/elasticsearch/queueprocessor.py index f0bffb2..77266d4 100644 --- a/src/collective/elasticsearch/queueprocessor.py +++ b/src/collective/elasticsearch/queueprocessor.py @@ -228,7 +228,7 @@ def get_data_for_es(self, uuid, attributes=None): if value in (None, "None"): # yes, we'll index null data... value = None - elif index_name in self._es_attributes: + elif index_name in self.es_attributes: indexer = queryMultiAdapter( (wrapped_object, catalog), IIndexer, name=index_name ) From 905da7cbc891c513a6d44f417b070c9174621442 Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Tue, 28 Feb 2023 13:10:47 -0500 Subject: [PATCH 4/8] Fix restriced object lookup while getting the data for elasticsearch. --- CHANGELOG.md | 2 ++ .../elasticsearch/queueprocessor.py | 3 ++- .../elasticsearch/tests/test_processor.py | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7fa5d..a0244c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - Tests: Wait for elasticsearch service @maethu +- Fix restricted object lookup @maethu + - Add support for highlight feature of elasticsearch @instification - Use _old_searchResults when patching safeSearchResults @instification diff --git a/src/collective/elasticsearch/queueprocessor.py b/src/collective/elasticsearch/queueprocessor.py index f0bffb2..585821b 100644 --- a/src/collective/elasticsearch/queueprocessor.py +++ b/src/collective/elasticsearch/queueprocessor.py @@ -8,6 +8,7 @@ from collective.elasticsearch.utils import getESOnlyIndexes from collective.elasticsearch.utils import use_redis from plone import api +from plone.app.uuid.utils import uuidToObject from plone.dexterity.utils import iterSchemata from plone.indexer.interfaces import IIndexableObject from plone.indexer.interfaces import IIndexer @@ -210,7 +211,7 @@ def get_data_for_redis(self, uuid, attributes=None): def get_data_for_es(self, uuid, attributes=None): """Data to be sent to elasticsearch.""" - obj = api.portal.get() if uuid == "/" else api.content.get(UID=uuid) + obj = api.portal.get() if uuid == "/" else uuidToObject(uuid, unrestricted=True) wrapped_object = self.wrap_object(obj) index_data = {} attributes = attributes if attributes else self.all_attributes diff --git a/src/collective/elasticsearch/tests/test_processor.py b/src/collective/elasticsearch/tests/test_processor.py index 0802e8f..4856e76 100644 --- a/src/collective/elasticsearch/tests/test_processor.py +++ b/src/collective/elasticsearch/tests/test_processor.py @@ -7,6 +7,8 @@ from plone import api from plone.app.contentrules.actions.move import MoveAction from plone.app.contentrules.tests.dummy import DummyEvent +from plone.app.testing import login +from plone.app.testing import TEST_USER_PASSWORD from plone.contentrules.rule.interfaces import IExecutable from Products.CMFCore.indexing import processQueue from zope.component import getMultiAdapter @@ -72,6 +74,26 @@ def test_moved_content(self): self.assertEqual(True, ex()) self.assertIn(obj_uid, processor.actions.index) + def test_index_even_if_access_to_obj_might_be_restricted(self): + processor = self.get_processor() + user = api.user.create( + username="worker", + email="ordinary_person@example.com", + password=TEST_USER_PASSWORD, + roles=("Member",), + ) + + folder = api.content.create(self.portal, "Folder", "folder1", title="A folder") + folder.manage_permission( + "Access contents information", roles=["Manager"], acquire=False + ) + obj = api.content.create(folder, "Event", "event1", title="Some Event") + + login(self.portal, user.getId()) + obj.reindexObject() + processQueue() + self.assertIn(obj.UID(), processor.actions.index) + @parameterized_class( [ From 6802428cc77c3fe0ede49f6eaaa30cd525fab2a9 Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Thu, 2 Feb 2023 18:41:58 -0500 Subject: [PATCH 5/8] Add plone.autoinclude for plone 6 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 8da12b9..4d51192 100644 --- a/setup.py +++ b/setup.py @@ -80,5 +80,7 @@ entry_points=""" [z3c.autoinclude.plugin] target = plone + [plone.autoinclude.plugin] + target = plone """, ) From 6d0ec67469b6df539331123edf61222c7246f023 Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Mon, 27 Feb 2023 10:03:32 -0500 Subject: [PATCH 6/8] No longer use global variables regarding redis from utils. Depeding on how the module got loaded (imported) the values were different. --- src/collective/elasticsearch/redis/fetch.py | 10 ++++------ src/collective/elasticsearch/testing.py | 10 ++++------ src/collective/elasticsearch/tests/__init__.py | 2 +- src/collective/elasticsearch/utils.py | 6 ------ 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/collective/elasticsearch/redis/fetch.py b/src/collective/elasticsearch/redis/fetch.py index 25526ed..29a5739 100644 --- a/src/collective/elasticsearch/redis/fetch.py +++ b/src/collective/elasticsearch/redis/fetch.py @@ -1,5 +1,3 @@ -from collective.elasticsearch import utils - import io import os import requests @@ -20,7 +18,8 @@ def fetch_data(uuid, attributes): - url = utils.PLONE_BACKEND + "/@elasticsearch_extractdata" + backend = os.environ.get("PLONE_BACKEND", None) + url = backend + "/@elasticsearch_extractdata" payload = {"uuid": uuid, "attributes:list": attributes} response = session.get(url, params=payload, verify=False, timeout=60) if response.status_code == 200: @@ -32,8 +31,7 @@ def fetch_data(uuid, attributes): def fetch_blob_data(fieldname, data): - download_url = "/".join( - [utils.PLONE_BACKEND, data[fieldname]["path"], "@@download", fieldname] - ) + backend = os.environ.get("PLONE_BACKEND", None) + download_url = "/".join([backend, data[fieldname]["path"], "@@download", fieldname]) file_ = session_data.get(download_url) return io.BytesIO(file_.content) diff --git a/src/collective/elasticsearch/testing.py b/src/collective/elasticsearch/testing.py index b0d0902..827207b 100644 --- a/src/collective/elasticsearch/testing.py +++ b/src/collective/elasticsearch/testing.py @@ -55,12 +55,10 @@ def setUpPloneSite(self, portal): super().setUpPloneSite(portal) # Setup environ for redis testing - os.environ["PLONE_BACKEND"] = utils.PLONE_BACKEND = portal.absolute_url() - os.environ["PLONE_USERNAME"] = utils.PLONE_USERNAME = SITE_OWNER_NAME - os.environ["PLONE_PASSWORD"] = utils.PLONE_PASSWORD = SITE_OWNER_PASSWORD - os.environ[ - "PLONE_REDIS_DSN" - ] = utils.PLONE_REDIS_DSN = "redis://localhost:6379/0" + os.environ["PLONE_BACKEND"] = portal.absolute_url() + os.environ["PLONE_USERNAME"] = SITE_OWNER_NAME + os.environ["PLONE_PASSWORD"] = SITE_OWNER_PASSWORD + os.environ["PLONE_REDIS_DSN"] = "redis://localhost:6379/0" # Make sure tasks are not handled async in tests # from collective.elasticsearch.redis.tasks import queue diff --git a/src/collective/elasticsearch/tests/__init__.py b/src/collective/elasticsearch/tests/__init__.py index 567fc15..49767ed 100644 --- a/src/collective/elasticsearch/tests/__init__.py +++ b/src/collective/elasticsearch/tests/__init__.py @@ -32,7 +32,7 @@ def setUp(self): self.request.environ["testing"] = True self.app = self.layer["app"] - os.environ["PLONE_BACKEND"] = utils.PLONE_BACKEND = self.portal.absolute_url() + os.environ["PLONE_BACKEND"] = self.portal.absolute_url() settings = utils.get_settings() # disable sniffing hosts in tests because docker... diff --git a/src/collective/elasticsearch/utils.py b/src/collective/elasticsearch/utils.py index 815b89a..98795dd 100644 --- a/src/collective/elasticsearch/utils.py +++ b/src/collective/elasticsearch/utils.py @@ -20,12 +20,6 @@ HAS_REDIS_MODULE = False -PLONE_REDIS_DSN = os.environ.get("PLONE_REDIS_DSN", None) -PLONE_USERNAME = os.environ.get("PLONE_USERNAME", None) -PLONE_PASSWORD = os.environ.get("PLONE_PASSWORD", None) -PLONE_BACKEND = os.environ.get("PLONE_BACKEND", None) - - def getUID(obj): value = IUUID(obj, None) if not value and hasattr(obj, "UID"): From eeba00e27e92211b968d46c72284d006b98be8b6 Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Wed, 1 Mar 2023 11:58:38 +0000 Subject: [PATCH 7/8] Add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7fa5d..b84f025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - Handle negative term filters (fixes #101) @instification +- Check addon is installed before processing queue (fixes #108) @instification + ## 5.0.0 (2022-10-11) - Rename `master` branch to `main` @ericof From 027abb1a4dc233660e5a43d5fba6172b2f2232de Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Tue, 28 Feb 2023 18:50:14 -0500 Subject: [PATCH 8/8] Add uuidToObject method for plone 5.2, which behaves like the one from plone 6. --- .../elasticsearch/queueprocessor.py | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/collective/elasticsearch/queueprocessor.py b/src/collective/elasticsearch/queueprocessor.py index 585821b..b329285 100644 --- a/src/collective/elasticsearch/queueprocessor.py +++ b/src/collective/elasticsearch/queueprocessor.py @@ -7,14 +7,16 @@ from collective.elasticsearch.manager import ElasticSearchManager from collective.elasticsearch.utils import getESOnlyIndexes from collective.elasticsearch.utils import use_redis +from pkg_resources import parse_version from plone import api -from plone.app.uuid.utils import uuidToObject +from plone.app.uuid.utils import uuidToCatalogBrain from plone.dexterity.utils import iterSchemata from plone.indexer.interfaces import IIndexableObject from plone.indexer.interfaces import IIndexer from plone.namedfile.interfaces import INamedBlobFileField from zope.component import getAdapters from zope.component import queryMultiAdapter +from zope.component.hooks import getSite from zope.globalrequest import getRequest from zope.interface import implementer from zope.schema import getFields @@ -22,6 +24,37 @@ import transaction +if parse_version(api.env.plone_version()) < parse_version("6"): + + def uuidToObject(uuid, unrestricted=False): + """Variation of this method, which support the parameter + 'unrestricted', like the one from plone 6. + """ + + brain = uuidToCatalogBrain(uuid) + if brain is None: + return None + + path = brain.getPath() + + if not path: + return + site = getSite() + if site is None: + return + # Go to the parent of the item without restrictions. + parent_path, final_path = path.rpartition("/")[::2] + parent = site.unrestrictedTraverse(parent_path) + # Do check restrictions for the final object. + # Check if the object has restrictions + if unrestricted: + return parent.unrestrictedTraverse(final_path) + return parent.restrictedTraverse(final_path) + +else: + from plone.app.uuid.utils import uuidToObject + + @implementer(IElasticSearchIndexQueueProcessor) class IndexProcessor: """A queue processor for elasticsearch"""