From 9664a0aacbebb17fd92d36eb36526c466fd8eaea Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 10 Oct 2026 10:16:18 +0200 Subject: [PATCH] Set a file field through its field manager, not the raw mutator A NamedFile or NamedImage field on a Dexterity type that also carries a BBB set mutator was written through the mutator, which stores the value exactly as it arrives. Over the API a file arrives as base64 text, so the field ended up holding the text rather than the file, and the object then failed its own validation with "wrong type" on that field. The data manager already goes through the field manager for the managers that normalize their value. NamedFileFieldManager does precisely that: it base64-decodes the payload and builds the NamedFile or NamedImage the field is declared to hold, taking the filename and content type from the payload. It belongs in that tuple, and NamedImageFieldManager comes with it as a subclass. Laboratory.accreditation_body_logo is the case that surfaced it: a NamedBlobImage with a setAccreditationBodyLogo mutator kept from the Archetypes schema. A field without such a mutator was never affected, which is why file fields have always been settable on the types that do not carry the BBB properties. --- docs/changelog.rst | 1 + src/senaite/jsonapi/datamanagers.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 3478b8d..21d4990 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,7 @@ Changelog applied. Uninstalling from the same panel removes the PAS plugin and the per-user JWT signing secrets. +- #118 Set a file field through its field manager, not the raw mutator - #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 diff --git a/src/senaite/jsonapi/datamanagers.py b/src/senaite/jsonapi/datamanagers.py index ad3d3e2..2a2cbe2 100644 --- a/src/senaite/jsonapi/datamanagers.py +++ b/src/senaite/jsonapi/datamanagers.py @@ -32,13 +32,23 @@ from senaite.jsonapi.interfaces import IDataManager from senaite.jsonapi.interfaces import IFieldManager from senaite.jsonapi.fieldmanagers import DurationFieldManager +from senaite.jsonapi.fieldmanagers import NamedFileFieldManager from senaite.jsonapi.fieldmanagers import UIDReferenceFieldMixin # Field managers that normalize the incoming value (resolve UIDs, coerce # a duration mapping to a timedelta, ...). For these the raw set # mutator would store the value unconverted, so the data manager must go # through the field manager instead of the setter. -NORMALIZING_FIELD_MANAGERS = (UIDReferenceFieldMixin, DurationFieldManager) +NORMALIZING_FIELD_MANAGERS = ( + UIDReferenceFieldMixin, + DurationFieldManager, + # A file arrives as base64 text and the manager decodes it and + # builds the NamedFile or NamedImage the field holds. The raw + # mutator would store the text itself, which the field then fails + # to validate as the wrong type. NamedImageFieldManager is a + # subclass, so it is covered here too. + NamedFileFieldManager, +) class BaseDataManager(object):