From a4e878a7354a8cc5f8d3c949a89a5bbe1d693953 Mon Sep 17 00:00:00 2001 From: irinaschubert Date: Mon, 2 Aug 2021 14:34:16 +0200 Subject: [PATCH] feat(resource-metadata): return resource metadata after metadata update request (DSP-1828) (#1893) * change response for update resource metadata request * Add new last modification date to response * add e2e tests * update documentation * remove option from lastModificationDate --- docs/03-apis/api-v2/editing-resources.md | 2 +- .../resourcemessages/ResourceMessagesV2.scala | 81 ++++++++++++++++++- .../responders/v2/ResourcesResponderV2.scala | 16 +++- .../e2e/v2/ResourcesRouteV2E2ESpec.scala | 36 ++++++++- .../v2/ResourcesResponderV2Spec.scala | 8 +- 5 files changed, 130 insertions(+), 13 deletions(-) diff --git a/docs/03-apis/api-v2/editing-resources.md b/docs/03-apis/api-v2/editing-resources.md index 9a6bfe5260..4082fe68a5 100644 --- a/docs/03-apis/api-v2/editing-resources.md +++ b/docs/03-apis/api-v2/editing-resources.md @@ -298,7 +298,7 @@ date, you will get an HTTP 409 (Conflict) error. If you submit a `knora-api:newModificationDate` that is earlier than the resource's `knora-api:lastModificationDate`, you will get an HTTP 400 (Bad Request) error. -A successful response is an HTTP 200 (OK) status containing a confirmation message. +A successful response is an HTTP 200 (OK) status containing the resource's metadata. ## Deleting a Resource diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala index 21171de41d..908821f409 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala @@ -21,7 +21,6 @@ package org.knora.webapi.messages.v2.responder.resourcemessages import java.time.Instant import java.util.UUID - import akka.actor.ActorRef import akka.event.LoggingAdapter import akka.pattern._ @@ -897,6 +896,86 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update } } +/** + * Represents a response after updating a resource's metadata. + * + * @param resourceIri the IRI of the resource. + * @param resourceClassIri the IRI of the resource class. + * @param lastModificationDate the resource's last modification date. + * @param maybeLabel the resource's new `rdfs:label`, if any. + * @param maybePermissions the resource's new permissions, if any. + * @param featureFactoryConfig the feature factory configuration. + */ +case class UpdateResourceMetadataResponseV2(resourceIri: IRI, + resourceClassIri: SmartIri, + lastModificationDate: Instant, + maybeLabel: Option[String] = None, + maybePermissions: Option[String] = None, + featureFactoryConfig: FeatureFactoryConfig) + extends KnoraJsonLDResponseV2 { + + /** + * Converts the response to a data structure that can be used to generate JSON-LD. + * + * @param targetSchema the Knora API schema to be used in the JSON-LD document. + * @return a [[JsonLDDocument]] representing the response. + */ + override protected def toJsonLDDocument(targetSchema: ApiV2Schema, + settings: KnoraSettingsImpl, + schemaOptions: Set[SchemaOption]): JsonLDDocument = { + + implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance + + // Make the knora-api prefix for the target schema. + + val knoraApiPrefixExpansion: IRI = targetSchema match { + case ApiV2Simple => OntologyConstants.KnoraApiV2Simple.KnoraApiV2PrefixExpansion + case ApiV2Complex => OntologyConstants.KnoraApiV2Complex.KnoraApiV2PrefixExpansion + } + + // Make the JSON-LD document. + + val context: JsonLDObject = JsonLDUtil.makeContext( + fixedPrefixes = Map( + "rdf" -> OntologyConstants.Rdf.RdfPrefixExpansion, + "rdfs" -> OntologyConstants.Rdfs.RdfsPrefixExpansion, + "xsd" -> OntologyConstants.Xsd.XsdPrefixExpansion, + OntologyConstants.KnoraApi.KnoraApiOntologyLabel -> knoraApiPrefixExpansion + ) + ) + + val label_map = maybeLabel match { + case Some(maybeLabel) => Map(OntologyConstants.Rdfs.Label -> JsonLDString(maybeLabel)) + case None => Map.empty[String, JsonLDValue] + } + + val lastModificationDate_map = + Map( + OntologyConstants.KnoraApiV2Complex.LastModificationDate -> JsonLDUtil.datatypeValueToJsonLDObject( + value = lastModificationDate.toString, + datatype = OntologyConstants.Xsd.DateTimeStamp.toSmartIri + )) + + val permissions_map = maybePermissions match { + case Some(maybePermissions) => + Map(OntologyConstants.KnoraApiV2Complex.HasPermissions -> JsonLDString(maybePermissions)) + case None => Map.empty[String, JsonLDValue] + } + + val resourceIri_resourceClassIri_map = + Map( + OntologyConstants.KnoraApiV2Complex.ResourceIri -> JsonLDString(resourceIri), + OntologyConstants.KnoraApiV2Complex.ResourceClassIri -> JsonLDString(resourceClassIri.toString) + ) + + val body = JsonLDObject( + resourceIri_resourceClassIri_map ++ label_map ++ lastModificationDate_map ++ permissions_map) + + JsonLDDocument(body = body, context = context) + + } +} + /** * Represents a request to mark a resource as deleted or to erase it from the triplestore. * diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala index 2debeb85d6..c5deb94310 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala @@ -364,11 +364,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * Updates a resources metadata. * * @param updateResourceMetadataRequestV2 the update request. - * @return a [[SuccessResponseV2]]. + * @return a [[UpdateResourceMetadataResponseV2]]. */ private def updateResourceMetadataV2( - updateResourceMetadataRequestV2: UpdateResourceMetadataRequestV2): Future[SuccessResponseV2] = { - def makeTaskFuture: Future[SuccessResponseV2] = { + updateResourceMetadataRequestV2: UpdateResourceMetadataRequestV2): Future[UpdateResourceMetadataResponseV2] = { + def makeTaskFuture: Future[UpdateResourceMetadataResponseV2] = { for { // Get the metadata of the resource to be updated. resourcesSeq: ReadResourcesSequenceV2 <- getResourcePreviewV2( @@ -487,7 +487,15 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt case None => FastFuture.successful(()) } - } yield SuccessResponseV2("Resource metadata updated") + } yield + UpdateResourceMetadataResponseV2( + resourceIri = updateResourceMetadataRequestV2.resourceIri, + resourceClassIri = updateResourceMetadataRequestV2.resourceClassIri, + maybeLabel = updateResourceMetadataRequestV2.maybeLabel, + maybePermissions = updateResourceMetadataRequestV2.maybePermissions, + lastModificationDate = newModificationDate, + featureFactoryConfig = updateResourceMetadataRequestV2.featureFactoryConfig + ) } for { diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala index 2e16e90bc3..797a948be8 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala @@ -22,7 +22,6 @@ package org.knora.webapi.e2e.v2 import java.net.URLEncoder import java.nio.file.Paths import java.time.Instant - import akka.actor.ActorSystem import akka.http.scaladsl.model.headers.{Accept, BasicHttpCredentials} import akka.http.scaladsl.model.{HttpEntity, HttpResponse, MediaRange, StatusCodes} @@ -90,6 +89,27 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { | } |}""".stripMargin + private def updateResourceMetadataResponse(newLastModificationDate: Instant, + maybeNewLabel: String, + resourceIri: String, + maybeNewPermissions: String): String = + s"""{ + | "knora-api:lastModificationDate": { + | "@value": "$newLastModificationDate", + | "@type": "xsd:dateTimeStamp" + | }, + | "rdfs:label": "$maybeNewLabel", + | "knora-api:resourceIri": "$resourceIri", + | "knora-api:hasPermissions": "$maybeNewPermissions", + | "knora-api:resourceClassIri": "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing", + | "@context": { + | "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + | "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + | "xsd": "http://www.w3.org/2001/XMLSchema#", + | "knora-api": "http://api.knora.org/ontology/knora-api/v2#" + | } + |}""".stripMargin + "The resources v2 endpoint" should { "perform a resource request for the book 'Reise ins Heilige Land' using the complex schema in JSON-LD" in { val request = Get(s"$baseApiUrl/v2/resources/${URLEncoder.encode("http://rdfh.ch/0803/2a6221216701", "UTF-8")}") @@ -1512,7 +1532,12 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val updateResponse: HttpResponse = singleAwaitingRequest(updateRequest) val updateResponseAsString: String = responseToString(updateResponse) assert(updateResponse.status == StatusCodes.OK, updateResponseAsString) - assert(JsonParser(updateResponseAsString) == JsonParser(successResponse("Resource metadata updated"))) + assert( + JsonParser(updateResponseAsString) == JsonParser( + updateResourceMetadataResponse(resourceIri = resourceIri, + maybeNewLabel = newLabel, + newLastModificationDate = newModificationDate, + maybeNewPermissions = newPermissions))) clientTestDataCollector.addFile( TestDataFileContent( @@ -1594,7 +1619,12 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val updateResponse: HttpResponse = singleAwaitingRequest(updateRequest) val updateResponseAsString: String = responseToString(updateResponse) assert(updateResponse.status == StatusCodes.OK, updateResponseAsString) - assert(JsonParser(updateResponseAsString) == JsonParser(successResponse("Resource metadata updated"))) + assert( + JsonParser(updateResponseAsString) == JsonParser( + updateResourceMetadataResponse(resourceIri = resourceIri, + maybeNewLabel = newLabel, + newLastModificationDate = newModificationDate, + maybeNewPermissions = newPermissions))) val previewRequest = Get(s"$baseApiUrl/v2/resourcespreview/${URLEncoder.encode(resourceIri, "UTF-8")}") ~> addCredentials( BasicHttpCredentials(anythingUserEmail, password)) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala index 3eecdbfd32..52026e4ba9 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala @@ -1762,7 +1762,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! updateRequest - expectMsgType[SuccessResponseV2](timeout) + expectMsgType[UpdateResourceMetadataResponseV2](timeout) // Get the resource from the triplestore and check it. @@ -1825,7 +1825,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! updateRequest - expectMsgType[SuccessResponseV2](timeout) + expectMsgType[UpdateResourceMetadataResponseV2](timeout) // Get the resource from the triplestore and check it. @@ -1869,7 +1869,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! updateRequest - expectMsgType[SuccessResponseV2](timeout) + expectMsgType[UpdateResourceMetadataResponseV2](timeout) // Get the resource from the triplestore and check it. @@ -2680,7 +2680,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { apiRequestID = UUID.randomUUID ) - expectMsgType[SuccessResponseV2](timeout) + expectMsgType[UpdateResourceMetadataResponseV2](timeout) responderManager ! ResourceHistoryEventsGetRequestV2( resourceIri = resourceIri,