Skip to content

Commit

Permalink
[fix] add adapter for fix relationfield deserializer
Browse files Browse the repository at this point in the history
  • Loading branch information
eikichi18 committed Dec 14, 2023
1 parent 3aacb1a commit 7ac980d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/redturtle/volto/restapi/deserializer/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
<!-- convert Link widget value in normalized url -->
<adapter factory=".dxfields.LinkTextLineFieldDeserializer" />

<!-- convert related string obj to obj -->
<adapter factory=".relationfield.RelationChoiceFieldDeserializer" />


<adapter factory=".dxfields.DatetimeFieldDeserializer" />

Expand Down
60 changes: 60 additions & 0 deletions src/redturtle/volto/restapi/deserializer/relationfield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from plone.dexterity.interfaces import IDexterityContent
from plone.restapi.deserializer.dxfields import DefaultFieldDeserializer
from plone.restapi.interfaces import IFieldDeserializer
from Products.CMFCore.utils import getToolByName
from redturtle.volto.interfaces import IRedturtleVoltoLayer
from z3c.relationfield.interfaces import IRelationChoice
from zope.component import adapter
from zope.component import getMultiAdapter
from zope.component import queryUtility
from zope.interface import implementer
from zope.intid.interfaces import IIntIds


@implementer(IFieldDeserializer)
@adapter(IRelationChoice, IDexterityContent, IRedturtleVoltoLayer)
class RelationChoiceFieldDeserializer(DefaultFieldDeserializer):
def __call__(self, value):
obj = None
resolved_by = None

if isinstance(value, dict):
# We are trying to deserialize the output of a serialization
# which is enhanced, extract it and put it on the loop again
value = value["UID"] if value.get("UID", None) else value["@id"]

if isinstance(value, int):
# Resolve by intid
intids = queryUtility(IIntIds)
obj = intids.queryObject(value)
resolved_by = "intid"
elif isinstance(value, str):
portal = getMultiAdapter(
(self.context, self.request), name="plone_portal_state"
).portal()
portal_url = portal.absolute_url()
if value.startswith(portal_url):
# Resolve by URL
obj = portal.restrictedTraverse(value[len(portal_url) + 1 :], None)
resolved_by = "URL"
elif value.startswith("/"):
# Resolve by path
obj = portal.restrictedTraverse(value.lstrip("/"), None)
resolved_by = "path"
else:
# Resolve by UID
catalog = getToolByName(self.context, "portal_catalog")
brain = catalog(UID=value)
if brain:
obj = brain[0].getObject()
resolved_by = "UID"

if obj is None:
self.request.response.setStatus(400)
msg = f"Could not resolve object for {value}"
if resolved_by:
msg += f" (resolved by {resolved_by})"
raise ValueError(msg)

self.field.validate(obj)
return obj

0 comments on commit 7ac980d

Please sign in to comment.