From b8f1594a968fb33c78205980e4414d1c4b429e2f Mon Sep 17 00:00:00 2001 From: David Glick Date: Tue, 21 Jan 2025 18:54:28 -0800 Subject: [PATCH 1/2] Update Plone test versions, and pin twine (#1865) * Update Plone test versions, and pin twine * Avoid overriding version pins * Remove Python 3.8 from the test matrix for Plone 6.0, where it is no longer supported * update test output for new minor Plone version --- .github/workflows/tests.yml | 2 -- news/1685.internal | 1 + plone-6.0.x-python3.8.cfg | 3 ++- plone-6.0.x.cfg | 17 ++--------------- plone-6.1.x.cfg | 9 +-------- requirements-6.0.txt | 2 +- requirements-6.1.txt | 2 +- .../tests/http-examples/registry_get_list.resp | 2 +- .../restapi/tests/http-examples/site_get.resp | 2 +- 9 files changed, 10 insertions(+), 30 deletions(-) create mode 100644 news/1685.internal diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 72d7ada3ff..bd31daf00a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,8 +10,6 @@ jobs: include: - python-version: "3.8" plone-version: "5.2" - - python-version: "3.8" - plone-version: "6.0" - python-version: "3.9" plone-version: "6.0" - python-version: "3.10" diff --git a/news/1685.internal b/news/1685.internal new file mode 100644 index 0000000000..6fe9f0e0dc --- /dev/null +++ b/news/1685.internal @@ -0,0 +1 @@ +Update CI. @davisagli diff --git a/plone-6.0.x-python3.8.cfg b/plone-6.0.x-python3.8.cfg index 2bd12daf3f..c093e32964 100644 --- a/plone-6.0.x-python3.8.cfg +++ b/plone-6.0.x-python3.8.cfg @@ -1,6 +1,6 @@ [buildout] extends = - https://dist.plone.org/release/6.0.12/versions.cfg + https://dist.plone.org/release/6.0.14/versions.cfg base.cfg [instance] @@ -15,3 +15,4 @@ robotframework-assertion-engine = 2.0.0 robotframework-debuglibrary = 2.3.0 robotframework-pythonlibcore = 4.2.0 grpcio-tools = 1.59.0 +twine = 5.1.1 diff --git a/plone-6.0.x.cfg b/plone-6.0.x.cfg index 26373fac81..eba5ea4141 100644 --- a/plone-6.0.x.cfg +++ b/plone-6.0.x.cfg @@ -1,24 +1,11 @@ [buildout] extends = - https://dist.plone.org/release/6.0.12/versions.cfg + https://dist.plone.org/release/6.0.14/versions.cfg base.cfg -[buildout:python37] -parts = - test - code-analysis - [instance] recipe = plone.recipe.zope2instance zodb-temporary-storage = off [versions] -# Override pin from Zope. https://github.com/zopefoundation/Zope/issues/1220 -docutils = 0.21.2 -pygments = 2.14.0 -plone.app.linkintegrity = 4.0.3 -robotframework-browser = 17.5.2 -robotframework-assertion-engine = 2.0.0 -robotframework-debuglibrary = 2.3.0 -robotframework-pythonlibcore = 4.2.0 -grpcio-tools = 1.59.0 +twine = 5.1.1 diff --git a/plone-6.1.x.cfg b/plone-6.1.x.cfg index 54716fa951..10bfe28308 100644 --- a/plone-6.1.x.cfg +++ b/plone-6.1.x.cfg @@ -1,17 +1,10 @@ [buildout] extends = - https://dist.plone.org/release/6.1.0a3/versions.cfg + https://dist.plone.org/release/6.1.0b2/versions.cfg base.cfg -[buildout:python37] -parts = - test - code-analysis - [instance] recipe = plone.recipe.zope2instance zodb-temporary-storage = off [versions] -# Override pin from Zope. https://github.com/zopefoundation/Zope/issues/1220 -docutils = 0.21.2 diff --git a/requirements-6.0.txt b/requirements-6.0.txt index b654a46a97..d75ea5cca5 100644 --- a/requirements-6.0.txt +++ b/requirements-6.0.txt @@ -1 +1 @@ --r https://dist.plone.org/release/6.0.12/requirements.txt +-r https://dist.plone.org/release/6.0.14/requirements.txt diff --git a/requirements-6.1.txt b/requirements-6.1.txt index 7ce0be7bb3..1abfefefc7 100644 --- a/requirements-6.1.txt +++ b/requirements-6.1.txt @@ -1 +1 @@ --r https://dist.plone.org/release/6.1.0a3/requirements.txt +-r https://dist.plone.org/release/6.1.0b2/requirements.txt diff --git a/src/plone/restapi/tests/http-examples/registry_get_list.resp b/src/plone/restapi/tests/http-examples/registry_get_list.resp index f172b2c8d1..213ccce065 100644 --- a/src/plone/restapi/tests/http-examples/registry_get_list.resp +++ b/src/plone/restapi/tests/http-examples/registry_get_list.resp @@ -423,5 +423,5 @@ Content-Type: application/json "value": "The person that created an item" } ], - "items_total": 2973 + "items_total": 2974 } diff --git a/src/plone/restapi/tests/http-examples/site_get.resp b/src/plone/restapi/tests/http-examples/site_get.resp index 43a502cc1e..417c0cbf83 100644 --- a/src/plone/restapi/tests/http-examples/site_get.resp +++ b/src/plone/restapi/tests/http-examples/site_get.resp @@ -4,7 +4,7 @@ Content-Type: application/json { "@id": "http://localhost:55001/plone/@site", "features": { - "filter_aliases_by_date": false + "filter_aliases_by_date": true }, "plone.allowed_sizes": [ "huge 1600:65536", From 88f2bc9cba9d2f3057813f8e0b4bc029ddcee117 Mon Sep 17 00:00:00 2001 From: Faakhir Zahid <110815427+Faakhir30@users.noreply.github.com> Date: Wed, 22 Jan 2025 08:01:56 +0500 Subject: [PATCH 2/2] add query param to search registry records. (#1861) * add query param to search registry records. * refactor serializer. * format using black. * use tmp registry isntead of seperate serializer class. * udpate http resp files * update docs. * update docs. * version added * Update docs/source/endpoints/registry.md * Apply suggestions from code review --------- Co-authored-by: Steve Piercy Co-authored-by: David Glick --- docs/source/endpoints/registry.md | 19 +++++++ news/1861.feature | 1 + src/plone/restapi/services/registry/get.py | 13 ++++- .../registry_get_list_filtered.req | 3 + .../registry_get_list_filtered.resp | 57 +++++++++++++++++++ src/plone/restapi/tests/test_documentation.py | 4 ++ src/plone/restapi/tests/test_registry.py | 9 +++ 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 news/1861.feature create mode 100644 src/plone/restapi/tests/http-examples/registry_get_list_filtered.req create mode 100644 src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp diff --git a/docs/source/endpoints/registry.md b/docs/source/endpoints/registry.md index 57fb9f3426..1a5e0a9c7f 100644 --- a/docs/source/endpoints/registry.md +++ b/docs/source/endpoints/registry.md @@ -52,6 +52,25 @@ Example response: :language: http ``` +## Filter list of registry records + +```{versionadded} plone.restapi 9.10.0 +``` + +You can filter a list of registry records and batch the results. +To do so, append a query string to the listing endpoint with a `q` parameter and its value set to the prefix of the desired record name. +See {doc}`../usage/batching` for details of how to work with batched results. + +```{eval-rst} +.. http:example:: curl httpie python-requests + :request: ../../../src/plone/restapi/tests/http-examples/registry_get_list_filtered.req +``` + +Example response: + +```{literalinclude} ../../../src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp +:language: http +``` ## Updating registry records diff --git a/news/1861.feature b/news/1861.feature new file mode 100644 index 0000000000..5e3538d612 --- /dev/null +++ b/news/1861.feature @@ -0,0 +1 @@ +In the `@registry` endpoint, added support for filtering the list of registry records. @Faakhir30 \ No newline at end of file diff --git a/src/plone/restapi/services/registry/get.py b/src/plone/restapi/services/registry/get.py index b75ecc07a4..689d712da3 100644 --- a/src/plone/restapi/services/registry/get.py +++ b/src/plone/restapi/services/registry/get.py @@ -1,3 +1,4 @@ +from plone.registry import Registry from plone.registry.interfaces import IRegistry from plone.restapi.interfaces import ISerializeToJson from plone.restapi.serializer.converters import json_compatible @@ -35,5 +36,15 @@ def reply(self): value = registry[self._get_record_name] return json_compatible(value) else: # batched listing - serializer = getMultiAdapter((registry, self.request), ISerializeToJson) + if q := self.request.form.get("q"): + + tmp_registry = Registry() + for key in registry.records.keys(): + if key.startswith(q): + tmp_registry.records[key] = registry.records[key] + registry = tmp_registry + serializer = getMultiAdapter( + (registry, self.request), + ISerializeToJson, + ) return serializer() diff --git a/src/plone/restapi/tests/http-examples/registry_get_list_filtered.req b/src/plone/restapi/tests/http-examples/registry_get_list_filtered.req new file mode 100644 index 0000000000..f9cfd8b3c8 --- /dev/null +++ b/src/plone/restapi/tests/http-examples/registry_get_list_filtered.req @@ -0,0 +1,3 @@ +GET /plone/@registry?q=Products.CMFPlone HTTP/1.1 +Accept: application/json +Authorization: Basic YWRtaW46c2VjcmV0 diff --git a/src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp b/src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp new file mode 100644 index 0000000000..8962fb5d70 --- /dev/null +++ b/src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp @@ -0,0 +1,57 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "@id": "http://localhost:55001/plone/@registry?q=Products.CMFPlone", + "items": [ + { + "name": "Products.CMFPlone.i18nl10n.override_dateformat.Enabled", + "schema": { + "properties": { + "description": "Override the translation machinery", + "factory": "Yes/No", + "title": "Enabled", + "type": "boolean" + } + }, + "value": false + }, + { + "name": "Products.CMFPlone.i18nl10n.override_dateformat.date_format_long", + "schema": { + "properties": { + "description": "Default value: %Y-%m-%d %H:%M (2038-01-19 03:14)", + "factory": "Text line (String)", + "title": "old ZMI property: localLongTimeFormat", + "type": "string" + } + }, + "value": "%Y-%m-%d %H:%M" + }, + { + "name": "Products.CMFPlone.i18nl10n.override_dateformat.date_format_short", + "schema": { + "properties": { + "description": "Default value: %Y-%m-%d (2038-01-19)", + "factory": "Text line (String)", + "title": "old ZMI property: localTimeFormat", + "type": "string" + } + }, + "value": "%Y-%m-%d" + }, + { + "name": "Products.CMFPlone.i18nl10n.override_dateformat.time_format", + "schema": { + "properties": { + "description": "Default value: %H:%M (03:14)", + "factory": "Text line (String)", + "title": "old ZMI property: localTimeOnlyFormat", + "type": "string" + } + }, + "value": "%H:%M" + } + ], + "items_total": 4 +} diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py index 574873ce6e..916f654b2a 100644 --- a/src/plone/restapi/tests/test_documentation.py +++ b/src/plone/restapi/tests/test_documentation.py @@ -549,6 +549,10 @@ def test_documentation_registry_get_list(self): response = self.api_session.get("/@registry") save_request_and_response_for_docs("registry_get_list", response) + def test_documentation_registry_get_list_filtered(self): + response = self.api_session.get("/@registry?q=Products.CMFPlone") + save_request_and_response_for_docs("registry_get_list_filtered", response) + def test_documentation_types(self): response = self.api_session.get("/@types") save_request_and_response_for_docs("types", response) diff --git a/src/plone/restapi/tests/test_registry.py b/src/plone/restapi/tests/test_registry.py index 61a266b644..069ca363cb 100644 --- a/src/plone/restapi/tests/test_registry.py +++ b/src/plone/restapi/tests/test_registry.py @@ -107,3 +107,12 @@ def test_get_listing(self): self.assertIn("items", response) self.assertIn("batching", response) self.assertIn("next", response["batching"]) + + def test_get_filtered_listing(self): + response = self.api_session.get("/@registry?q=foo.bar1") + self.assertEqual(response.status_code, 200) + response = response.json() + # 10 records from foo.bar10 to foo.bar19 and 1 record foo.bar1 + self.assertEqual(len(response["items"]), 11) + self.assertEqual(response["items"][0]["name"], "foo.bar1") + self.assertEqual(response["items"][0]["value"], "Lorem Ipsum")