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.

- #91 Add DataGridFieldManager to fix UID reference validation in DataGrid fields
- #90 Fix JWT authentication security issues
- #88 Add Bearer token (JWT) authentication via PAS plugin
- #89 Fix inherited schema fields missing for multi-schema Dexterity types
Expand Down
5 changes: 5 additions & 0 deletions src/senaite/jsonapi/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@
factory=".fieldmanagers.DXUIDReferenceFieldManager"
/>

<!-- Adapter for DX DataGridField Field -->
<adapter
for="senaite.core.schema.interfaces.IDataGridField"
factory=".fieldmanagers.DataGridFieldManager"
/>

<!-- ZOPE SCHEMA FIELD MANAGERS
Field level interface to get and set values and get a JSON compatible
Expand Down
31 changes: 31 additions & 0 deletions src/senaite/jsonapi/fieldmanagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
from AccessControl import Unauthorized
from DateTime import DateTime
from Products.Archetypes.utils import mapply
from senaite.core.schema.uidreferencefield import UIDReferenceField
from senaite.jsonapi import api
from senaite.jsonapi import logger
from senaite.jsonapi import underscore as u
from senaite.jsonapi.interfaces import IFieldManager
from zope import interface
from zope.interface import implementer
from zope.schema import getFields
from zope.schema._bootstrapinterfaces import WrongContainedType
from zope.schema._bootstrapinterfaces import WrongType

Expand Down Expand Up @@ -94,6 +96,35 @@ def _get(self, instance, **kw):
return self.field.get(instance)


class DataGridFieldManager(ZopeSchemaFieldManager):
"""Adapter to get/set the value of DataGridField (grid/records) fields
"""
interface.implements(IFieldManager)

def _normalize_datagrid(self, value):
schema = self.field.value_type.schema

for row in value:
for name, field in getFields(schema).items():
if isinstance(field, UIDReferenceField):
uid = row.get(name)
if not uid:
continue
# UIDReferenceField sub-fields nested inside a DataGridRow
# always require a list of native `str` UIDs
if isinstance(uid, list):
row[name] = [str(u) for u in uid]
else:
row[name] = [str(uid)]
return value

def set(self, instance, value, **kw):
"""Set the value of the field
"""
value = self._normalize_datagrid(value)
return self._set(instance, value, **kw)


class DatetimeFieldManager(ZopeSchemaFieldManager):
"""Adapter to get/set the value of Datetime Fields
"""
Expand Down