feat: add per-resource authorship property with read and write-on-create (DEV-6662)#4157
feat: add per-resource authorship property with read and write-on-create (DEV-6662)#4157danielasubotic wants to merge 5 commits into
Conversation
…ate (DEV-6662) Adds the built-in knora-base:hasResourceAuthorship property (data-side authorship on the resource node), bumps the ontology version 51->52, and implements the read path (resource GET serialises it) and write-on-create (POST /v2/resources persists it). The post-create edit endpoint is split into DEV-6669 (api-2b). 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 |
…ion (DEV-6662) The /v2/resources create parser iterated all non-metadata predicates as value properties; the new knora-base:hasResourceAuthorship literals were parsed as values, causing a 500 (Jena ResourceRequiredException) on create. Add it to the filtered (metadata) predicates — it is read separately via RootResource.resourceAuthorship. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uthorship (DEV-6662) The new per-resource authorship property (knora-api:hasResourceAuthorship) changes generated output that several tests assert against. No production code changes. - GetResourcePropertiesAndValuesQuerySpec: add the hasResourceAuthorship triple (CONSTRUCT) and OPTIONAL (WHERE) to the 12 expected SPARQL queries. - Ontology format fixtures: regenerate the ontology JSON-LD fixtures (knora-api + anything) that now carry the inherited hasResourceAuthorship cardinality and the property definition. The matching .ttl is regenerated too (and reordered by the Turtle serializer) so it stays isomorphic with the JSON-LD, as JsonLDUtilSpec asserts. - ApiComplexV2JsonLdRequestParserSpec: compare resourceAuthorship as an unordered set. Authorship is a plain multi-valued datatype property whose order does not round-trip (no rdf:List, no ORDER BY on read), consistent with asset-side authorship. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4157 +/- ##
==========================================
- Coverage 85.98% 85.96% -0.02%
==========================================
Files 538 539 +1
Lines 30571 30578 +7
Branches 3559 3558 -1
==========================================
Hits 26286 26286
- Misses 4285 4292 +7
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:
|
…resource (DEV-6475) The resource read mapped persisted knora-base:hasResourceAuthorship values via Authorship.unsafeFrom, so any value that fails Authorship validation (e.g. written out-of-band by tools or imported data) threw and turned every GET of that resource into a 500. Parse leniently with Authorship.from and drop invalid values so the resource stays readable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes DEV-6662
Motivation
The resource-side legal-metadata feature needs per-resource authorship so a data record can credit its authors independently of the project default and of file-level authorship. This is api-2 of the roadmap (spec: dasch-specs
03-feat-legal-metadata-resource-side-plan.md§4.B). It follows api-1 (project-level fields, dsp-api#4156) and is deployed alongside it.Summary
Adds a new built-in property
knora-base:hasResourceAuthorship(a flat datatype property on the resource node) and the read and write-on-create paths for it. The heavier, no-precedent post-create edit endpoint is split into DEV-6669 (api-2b) so it gets a focused, design-first PR.This split aligns with the frontend: app-3's create-form (set authorship at creation) needs only this PR; only its inline edit needs api-2b.
Key Changes
knora-base:hasResourceAuthorship(subjectClassConstraint:Resource, minCardinality 0);KnoraBaseVersion51→52 with aMigrateOnlyBuiltInGraphsplugin registered for v52 (built-in-graph reload, no data migration — also reloads api-1's knora-admin additions). Mirrored inOntologyConstants(KnoraBase + KnoraApiV2) andKnoraBaseToApiV2ComplexTransformationRules(datatype property, subjectTypeknora-api:Resource).resourceAuthorshiponReadResourceV2+toJsonLD(emitted only when set); extracted inConstructResponseUtilV2; andGetResourcePropertiesAndValuesQueryextended (CONSTRUCT + OPTIONAL WHERE) because it enumerates resource predicates rather than returning them all.POST /v2/resourcesJSON-LD (ApiComplexV2JsonLdRequestParser), carried onCreateResourceV2, threaded toResourceReadyToCreate, and written as one triple per author inResourcesRepoLive(no triples when empty).knora-base.mdResources section.Challenges and Decisions
KnoraBaseVersionwas already 51; the established pattern (seeRepositoryUpdatePlanv51) is to bump and register aMigrateOnlyBuiltInGraphsplugin — not a custom data migration. Done for v52.GetResourcePropertiesAndValuesQuerylists resource-node predicates explicitly, so a new predicate is not returned automatically — I addedhasResourceAuthorshipto both the CONSTRUCT template and an OPTIONAL WHERE pattern.Gotchas
OntologyFormatsE2ESpeccompares the served knora-api ontology totest_data/generated_test_data/ontologyR2RV2/knoraApiOntologyWithValueObjects.jsonldand rewrites it on diff. The new property changes that output, so the fixture must be regenerated by running that e2e spec against the stack (it can't be produced without it). This spec will be red in CI until the regenerated fixture is committed — hence draft.Test Plan
ApiComplexV2JsonLdRequestParserSpec—createResourceRequestV2populatesresourceAuthorshipfromknora-api:hasResourceAuthorshipand leaves it empty when absent.webapi/compileandwebapi/Test/compilegreen locally;sbt fmtapplied.🤖 Generated with Claude Code