feat: add post-create resource authorship edit endpoint (DEV-6669)#4158
Conversation
Adds PUT /v2/resources/authorship to replace a resource's data-side authorship after creation, gated by Modify object-access permission. Modelled on updateResourceMetadataV2, with a new ChangeResourceAuthorshipQuery SPARQL update. Stacked on the api-2 branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Related PRs — resource-side legal metadata (R5-SC-04 / DEV-6475)This is one of three coordinated dsp-api PRs for the feature (project fields → #4156, per-resource authorship property → #4157, edit endpoint → #4158). Downstream consumer PRs:
The api PRs deploy together; dsp-app regenerates its OpenAPI client from the deployed api and dsp-tools calls the JSON API directly. For local end-to-end testing, all three dsp-api PRs are combined on the |
…thorship' into feature/dev-6669-resource-authorship-edit
The updateResourceAuthorshipRequestV2 parse test compared authorship as an ordered Seq, but authorship is a plain multi-valued datatype property (no rdf:List, no ORDER BY on read), so order does not round-trip through the triplestore. Compare as an unordered set, matching the createResourceRequestV2 test fixed on the base branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feature/dev-6662-per-resource-authorship #4158 +/- ##
============================================================================
- Coverage 86.00% 85.80% -0.21%
============================================================================
Files 539 540 +1
Lines 30539 30656 +117
Branches 3558 3554 -4
============================================================================
+ Hits 26265 26304 +39
- Misses 4274 4352 +78
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…rsisted (DEV-6669) The resource authorship and metadata update queries scoped the named project graph onto only the DELETE/INSERT templates (via .from/.into) and left the WHERE clause ungraphed. That makes the update depend on the triplestore's union-default-graph being enabled for the WHERE to match the resource; on a triplestore without it, the WHERE matches nothing and the whole update silently no-ops. Use `WITH <graph>` so the named project graph applies to DELETE, INSERT and WHERE alike, independent of the union-default-graph setting. Also verify in the responder that the authorship was actually persisted — not only that the lastModificationDate advanced — and fail with UpdateNotPerformedException otherwise, so a no-op surfaces as an error instead of a misleading 200. Add ChangeResourceAuthorshipQuerySpec and update ChangeResourceMetadataQuerySpec to assert the WITH form (no GRAPH wrapper). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace a double-arrow (U+21D2) and two em-dashes (U+2014) introduced in earlier comments with `=>` and `--`, per the ASCII-only convention for src/main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes DEV-6669
Motivation
api-2 (#4157) added the
knora-base:hasResourceAuthorshipproperty with read + write-on-create. This PR (api-2b) adds the post-create edit path so a resource's authorship can be changed after creation — needed by dsp-app app-3's inline authorship edit (DEV-6667). It was split out of api-2 because it has no FileValue precedent and warranted a focused, design-first PR (spec §4.B).Summary
A new
Modify-gated endpointPUT /v2/resources/authorshipthat replaces a resource's authorship (an empty list clears it). Modeled end-to-end on the existingupdateResourceMetadataV2chain.Key Changes
ResourceMessagesV2):UpdateResourceAuthorshipRequestV2+UpdateResourceAuthorshipResponseV2(withtoJsonLDDocumentemittingknora-api:hasResourceAuthorship+ the newlastModificationDate).ApiComplexV2JsonLdRequestParser):updateResourceAuthorshipRequestV2(reuses theresourceAuthorshipaccessor added in api-2).ChangeResourceAuthorshipQuery, new): mirrorsChangeResourceMetadataQuery— DELETE the oldhasResourceAuthorshiptriples + last-mod-date, INSERT the new authorship (one triple per author) + new last-mod-date, with the same optimistic-locklastModificationDateWHERE handling.ResourcesResponderV2.updateResourceAuthorshipV2):IriLocker, class check,ensureNoConflictingChange,checkResourcePermission(_, Permission.ObjectAccess.Modify, _), run the update, verify the new last-mod-date.putResourcesAuthorshipinResourcesEndpoints, wired throughResourcesServerEndpointsandResourcesRestService.Challenges and Decisions
?oldAuthorshipand re-inserts the new set.Modifyobject-access on the resource (server-side, via the sharedResourceUtilV2.checkResourcePermission) — a non-Modifyuser gets 403, matching WB-2.Gotchas
knoraApiOntologyWithValueObjects.jsonldwith the stack) since it builds on that branch.Test Plan
ApiComplexV2JsonLdRequestParserSpec—updateResourceAuthorshipRequestV2parses the resource IRI and the new authorship.webapi/compileandwebapi/Test/compilegreen;sbt fmtapplied.🤖 Generated with Claude Code