Skip to content

Commit

Permalink
Prevent create an empty item. Temporarily completely overrided `Deser…
Browse files Browse the repository at this point in the history
…ializeFromJson.__call__` from `plone.restapi` until issue plone/plone.restapi#1386 is fixed.

See #PM-3869
  • Loading branch information
gbastien committed Apr 27, 2022
1 parent 5681bf6 commit 8e6f685
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Changelog

- Enable environment variable `RESTAPI_DEBUG` in tests.
[gbastien]
- Prevent create an empty item. Temporarily completely overrided
`DeserializeFromJson.__call__` from `plone.restapi` until issue
https://github.com/plone/plone.restapi/issues/1386 is fixed.
[gbastien]

1.0rc12 (2022-02-15)
--------------------
Expand Down
69 changes: 66 additions & 3 deletions src/plonemeeting/restapi/deserializer/atcontent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
from plone.restapi.deserializer import json_body
from plone.restapi.deserializer.atcontent import DeserializeFromJson as ATDeserializeFromJson
from plone.restapi.interfaces import IDeserializeFromJson
from plone.restapi.interfaces import IFieldDeserializer
from Products.Archetypes.event import ObjectEditedEvent
from Products.Archetypes.event import ObjectInitializedEvent
from Products.PloneMeeting.interfaces import IATMeetingContent
from zExceptions import BadRequest
from zope.component import adapter
from zope.component import queryMultiAdapter
from zope.event import notify
from zope.interface import implementer
from zope.interface import Interface

Expand All @@ -28,9 +34,66 @@ def __call__(self, validate_all=False, data=None, create=False):
wfTool = api.portal.get_tool("portal_workflow")
wf = wfTool.getWorkflowsFor(self.context)[0]
wf.updateRoleMappingsFor(self.context)
return super(DeserializeFromJson, self).__call__(
validate_all=validate_all, data=data, create=create
)

# XXX overrided until https://github.com/plone/plone.restapi/pull/1387 is merged
#return super(DeserializeFromJson, self).__call__(
# validate_all=validate_all, data=data, create=create
#)

if data is None:
data = json_body(self.request)

obj = self.context
modified = False

for field in obj.Schema().fields():
if not field.writeable(obj):
continue

name = field.getName()

if name in data:
deserializer = queryMultiAdapter(
(field, obj, self.request), IFieldDeserializer
)
if deserializer is None:
continue
value, kwargs = deserializer(data[name])
mutator = field.getMutator(obj)
mutator(value, **kwargs)
modified = True

if create or modified:
errors = self.validate()
if not validate_all:
errors = {f: e for f, e in errors.items() if f in data}
if errors:
errors = [
{"message": e, "field": f, "error": "ValidationError"}
for f, e in errors.items()
]
raise BadRequest(errors)

if create:
if obj.checkCreationFlag():
obj.unmarkCreationFlag()
notify(ObjectInitializedEvent(obj))
obj.at_post_create_script()
else:
obj.reindexObject()
notify(ObjectEditedEvent(obj))
obj.at_post_edit_script()

# We'll set the layout after the validation and and even if there
# are no other changes.
if "layout" in data:
layout = data["layout"]
self.context.setLayout(layout)

# OrderingMixin
self.handle_ordering(data)

return obj

def validate(self):
"""Handle "ignore_validation_for" that will specifically
Expand Down
16 changes: 16 additions & 0 deletions src/plonemeeting/restapi/tests/test_services_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,22 @@ def test_restapi_add_clean_meeting(self):
u"'error': 'ValidationError'}]",
u'type': u'BadRequest'})

def test_restapi_add_item_can_not_create_empty(self):
"""Test that an empty item can not be created."""
cfg = self.meetingConfig
self.changeUser("pmManager")
endpoint_url = "{0}/@item".format(self.portal_url)
json = {"config_id": cfg.getId()}
response = self.api_session.post(endpoint_url, json=json)
self.assertEqual(response.status_code, 400, response.content)
self.assertEqual(
response.json(),
{u'message':
u"[{'field': 'proposingGroup', 'message': u'A proposing group is required.', "
u"'error': 'ValidationError'}, {'field': 'title', 'message': u'Purpose is required, "
u"please correct.', 'error': 'ValidationError'}]", u'type': u'BadRequest'}
)


class testServiceAddWithAnnexes(BaseTestCase):
"""@item/@meeting POST endpoints with annexes."""
Expand Down

0 comments on commit 8e6f685

Please sign in to comment.