Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Changelog
applied. Uninstalling from the same panel removes the PAS plugin
and the per-user JWT signing secrets.

- #110 Fix /registry route failing on datetime registry values
- #109 Add a partition operation endpoint
- #106 Fix single-valued UID reference fields not settable through the JSON API
- #112 Allow updating the Laboratory through the API
Expand Down
26 changes: 25 additions & 1 deletion src/senaite/jsonapi/api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from Products.CMFPlone.interfaces.controlpanel import IMaintenanceSchema
from Products.CMFPlone.interfaces.controlpanel import ISecuritySchema
from Products.CMFPlone.interfaces.controlpanel import IUserGroupsSettingsSchema # noqa: E501
from senaite.core.api import dtime
from zope.component import getAdapter
from zope.schema import getFieldNames

Expand All @@ -46,6 +47,28 @@
}


def to_json_value(value):
"""Coerce a registry value into a JSON serializable form.

Registry records may hold dates or datetimes (and containers of them),
which the JSON encoder used by the route cannot serialize.

:param value: The raw registry value
:returns: A JSON serializable value
"""
if isinstance(value, (list, tuple)):
return [to_json_value(item) for item in value]
if isinstance(value, dict):
return {key: to_json_value(val) for key, val in value.items()}
# datetime and Zope DateTime
if dtime.is_dt(value) or dtime.is_DT(value):
return dtime.to_iso_format(value)
# pure date, which to_iso_format does not handle
if dtime.is_d(value):
return value.isoformat()
return value


def get_registry_records_by_keyword(keyword=None):
"""Return registry records whose name contains `keyword`.

Expand All @@ -55,7 +78,8 @@ def get_registry_records_by_keyword(keyword=None):
records = {}
for record in portal_reg.records:
if keyword is None or keyword.lower() in record.lower():
records[record] = bika_api.get_registry_record(record)
value = bika_api.get_registry_record(record)
records[record] = to_json_value(value)
return records


Expand Down
25 changes: 25 additions & 0 deletions src/senaite/jsonapi/tests/doctests/api_settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,31 @@ filtered subset:
True


Non JSON serializable values are coerced
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some registry records hold `datetime` values, which the JSON encoder used
by the route cannot serialize. Such values are coerced to ISO strings:

>>> from datetime import datetime
>>> from plone.registry import field
>>> from plone.registry.record import Record
>>> reg = ploneapi.portal.get_tool("portal_registry")
>>> reg.records["senaite.jsonapi.test_datetime"] = Record(
... field.Datetime(title=u"Test"),
... datetime(2014, 8, 14, 0, 0, 0, 3))
>>> transaction.commit()

>>> hits = api_settings.get_registry_records_by_keyword("test_datetime")
>>> hits["senaite.jsonapi.test_datetime"]
'2014-08-14T00:00:00.000003'

So the whole record set is now JSON serializable:

>>> ignored = json.dumps(
... api_settings.get_registry_records_by_keyword(None))


get_settings_by_keyword via the /settings route
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
Loading