Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
53220bf
Require Manage portal permission for /registry and /settings
ramonski Jul 25, 2026
67930d5
Restrict /users listing to managers to prevent enumeration
ramonski Jul 25, 2026
b3b514a
Log deprecation warning on GET /login with credentials
ramonski Jul 25, 2026
27c4038
Add changelog entry for #92
ramonski Jul 25, 2026
9712c17
Merge remote-tracking branch 'origin/2.x' into security/pr-b
ramonski Jul 25, 2026
ad149e0
Use fixture cookie-login for Manager path in security_fixes doctest
ramonski Jul 25, 2026
1385d5f
Drop redundant Manager positive-path assertion in security_fixes
ramonski Jul 25, 2026
564f533
Convert api module to package for future extractions
ramonski Jul 25, 2026
acecdd7
Extract user helpers to senaite.jsonapi.api.users
ramonski Jul 25, 2026
47cf768
Add changelog entry for #93
ramonski Jul 25, 2026
e2fd102
Extract registry and settings helpers to api/settings
ramonski Jul 25, 2026
c2e23b9
Add changelog entry for #94
ramonski Jul 25, 2026
bd22f32
Add direct-call doctest for api.settings
ramonski Jul 25, 2026
82a0d2b
Drop now-unused getAdapter import
ramonski Jul 25, 2026
300237a
Add real-value assertions to api.settings doctest
ramonski Jul 25, 2026
3483e73
Use cookie-login browser for /settings positive path
ramonski Jul 25, 2026
908f2dc
Extract serialization helpers to api/serialization
ramonski Jul 25, 2026
5298bfb
Add changelog entry for #95
ramonski Jul 25, 2026
e5aa41d
Add direct-call doctest for api.serialization
ramonski Jul 25, 2026
ed52aac
Add typed exception subclasses for the JSON API error envelope
ramonski Jul 25, 2026
adfe046
Add changelog entry for #96
ramonski Jul 25, 2026
dccc934
Extract create/update/delete helpers to api/mutation
ramonski Jul 25, 2026
4a53157
Add changelog entry for #97
ramonski Jul 25, 2026
e40f25b
Accept REST verbs PUT/PATCH/DELETE on the action route
ramonski Jul 25, 2026
4dd0a8e
Add changelog entry for #98
ramonski Jul 25, 2026
744b78f
Add WebDAV verb bypass so PUT/PATCH/DELETE reliably reach the API
ramonski Jul 25, 2026
7ddaf3b
Report the reason when object creation fails
ramonski Jul 27, 2026
2c4860d
Add changelog entry for #99
ramonski Jul 27, 2026
9422c88
Merge branch '2.x' into feature/report-create-errors
xispa Oct 5, 2026
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.

- #99 Report the reason when object creation fails
- #98 Accept REST verbs PUT/PATCH/DELETE on the action route
- #97 Extract create/update/delete helpers to api/mutation
- #96 Add typed exception subclasses for the JSON API error envelope
Expand Down
11 changes: 10 additions & 1 deletion src/senaite/jsonapi/api/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def create_items(portal_type=None, uid=None, endpoint=None, **kw):
records = req.get_request_data()

results = []
errors = []
for record in records:
if portal_type is None:
portal_type = record.pop("portal_type", None)
Expand All @@ -111,9 +112,17 @@ def create_items(portal_type=None, uid=None, endpoint=None, **kw):
except Exception as e:
sp.rollback()
logger.exception("Error while creating object: %s", e)
errors.append(str(e))

if not results:
raise BadRequestError("No Objects could be created")
# Surface the underlying reason(s) -- e.g. missing required
# fields reported by the object's validation ({"field": "required
# field"}) -- instead of a generic failure, so the caller sees
# exactly what to fix.
detail = "; ".join(filter(None, errors))
raise BadRequestError(
"No objects could be created: {}".format(detail)
if detail else "No objects could be created")

return make_items_for(results, endpoint=endpoint)

Expand Down
Loading