diff --git a/src/plone/restapi/search/handler.py b/src/plone/restapi/search/handler.py index 64a6f90e3..2a362e05d 100644 --- a/src/plone/restapi/search/handler.py +++ b/src/plone/restapi/search/handler.py @@ -77,7 +77,7 @@ def _constrain_query_by_path(self, query): def quote_chars(self, query): # Remove parentheses from the query - return query.replace("(", "").replace(")", "").strip() + return query.replace("(", " ").replace(")", " ").strip() def search(self, query=None): if query is None: @@ -110,7 +110,6 @@ def search(self, query=None): results = getMultiAdapter((lazy_resultset, self.request), ISerializeToJson)( fullobjects=fullobjects ) - return results def filter_types(self, types): diff --git a/src/plone/restapi/tests/test_search.py b/src/plone/restapi/tests/test_search.py index e4ddb4c38..081612ace 100644 --- a/src/plone/restapi/tests/test_search.py +++ b/src/plone/restapi/tests/test_search.py @@ -151,6 +151,23 @@ def test_search_on_context_constrains_query_by_path(self): set(result_paths(response.json())), ) + def test_search_with_parentheses(self): + query = {"SearchableText": "("} + response = self.api_session.get("/@search", params=query) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [], "Expected no items for query with only parentheses") + + query = {"SearchableText": ")"} + response = self.api_session.get("/@search", params=query) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [], "Expected no items for query with only parentheses") + + query = {"SearchableText": "lorem(ipsum)"} + response = self.api_session.get("/@search", params=query) + self.assertEqual(response.status_code, 200) + items = [item["title"] for item in response.json().get("items", [])] + self.assertIn("Lorem Ipsum", items, "Expected 'Lorem Ipsum' to be found in search results") + def test_search_in_vhm(self): # Install a Virtual Host Monster if "virtual_hosting" not in self.app.objectIds():