Skip to content

Commit 0fbe5a8

Browse files
author
Benjamin Geer
authored
feat(api-v2): Accept custom timestamps in update/delete requests (#1686)
1 parent fa48e61 commit 0fbe5a8

16 files changed

Lines changed: 785 additions & 195 deletions

File tree

‎docs/03-apis/api-v2/editing-resources.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ The request body is a JSON-LD object containing the following information about
330330
The optional property `knora-api:deleteComment` specifies a comment to be attached to the
331331
resource, explaining why it has been marked as deleted.
332332

333+
The optional property `knora-api:deleteDate`
334+
(an [xsd:dateTimeStamp](https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp))
335+
indicates when the resource was marked as deleted; if not given, the current
336+
time is used.
337+
333338
The response is a JSON-LD document containing the predicate `knora-api:result`
334339
with a confirmation message.
335340

‎docs/03-apis/api-v2/editing-values.md‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ Permissions for the new value can be given by adding `knora-api:hasPermissions`.
8383
}
8484
}
8585
```
86+
8687
Each value can have an optional custom IRI (of [Knora IRI](knora-iris.md#iris-for-data) form) specified by the `@id` attribute, a custom creation date specified by adding
87-
`knora-api:creationDate` (an [xsd:dateTimeStamp](https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp)), or a custom UUID
88+
`knora-api:valueCreationDate` (an [xsd:dateTimeStamp](https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp)), or a custom UUID
8889
given by `knora-api:valueHasUUID`. Each custom UUID must be [base64url-encoded](rfc:4648#section-5), without padding.
8990
For example:
9091

@@ -97,7 +98,7 @@ For example:
9798
"@type" : "knora-api:IntValue",
9899
"knora-api:intValueAsInt" : 21,
99100
"knora-api:valueHasUUID" : "IN4R19yYR0ygi3K2VEHpUQ",
100-
"knora-api:creationDate" : {
101+
"knora-api:valueCreationDate" : {
101102
"@type" : "xsd:dateTimeStamp",
102103
"@value" : "2020-06-04T12:58:54.502951Z"
103104
}
@@ -108,6 +109,7 @@ For example:
108109
"xsd" : "http://www.w3.org/2001/XMLSchema#"
109110
}
110111
```
112+
111113
The format of the object of `knora-api:hasPermissions` is described in
112114
[Permissions](../../02-knora-ontologies/knora-base.md#permissions).
113115

@@ -386,6 +388,9 @@ To update only the permissions on a value, submit it with the new permissions an
386388
To update a link, the user must have **modify permission** on the containing resource as
387389
well as on the value.
388390

391+
To update a value and give it a custom timestamp, add
392+
`knora-api:valueCreationDate` (an [xsd:dateTimeStamp](https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp)).
393+
389394
The response is a JSON-LD document containing only `@id` and `@type`, returning the IRI
390395
and type of the new value version.
391396

@@ -431,7 +436,10 @@ the resource to the value, and the value's ID and type. For example:
431436
```
432437

433438
The optional property `knora-api:deleteComment` specifies a comment to be attached to the
434-
value, explaining why it has been marked as deleted.
439+
value, explaining why it has been marked as deleted
440+
441+
The optional property `knora-api:deleteDate` (an [xsd:dateTimeStamp](https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp))
442+
specifies a custom timestamp indicating when the value was deleted. If not specified, the current time is used.
435443

436444
The response is a JSON-LD document containing the predicate `knora-api:result`
437445
with a confirmation message.

‎webapi/src/main/scala/org/knora/webapi/messages/util/JsonLDUtil.scala‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,16 +461,13 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue {
461461
}
462462

463463
/**
464-
* Validates the optional `uuid` of a JSON-LD object as a value uuid.
464+
* Validates an optional Base64-encoded UUID in a JSON-LD object.
465465
*
466466
* @return an optional validated decoded UUID.
467467
*/
468-
def maybeUUID: Option[UUID] = {
468+
def maybeUUID(key: String): Option[UUID] = {
469469
implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance
470-
471-
val maybeUUID: Option[UUID] = maybeStringWithValidation(OntologyConstants.KnoraApiV2Complex.ValueHasUUID, stringFormatter.validateBase64EncodedUuid)
472-
473-
maybeUUID
470+
maybeStringWithValidation(key, stringFormatter.validateBase64EncodedUuid)
474471
}
475472

476473
/**
@@ -678,6 +675,11 @@ case class JsonLDDocument(body: JsonLDObject, context: JsonLDObject = JsonLDObje
678675
*/
679676
def requireResourcePropertyValue: (SmartIri, JsonLDObject) = body.requireResourcePropertyApiV2ComplexValue
680677

678+
/**
679+
* A convenience function that calls `body.maybeUUID`.
680+
*/
681+
def maybeUUID(key: String): Option[UUID] = body.maybeUUID(key: String)
682+
681683
/**
682684
* Converts this JSON-LD object to its compacted Java representation.
683685
*/

‎webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala‎

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -584,13 +584,12 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource
584584
OntologyConstants.KnoraApiV2Complex.CreationDate
585585
)
586586

587-
valueFutures: Map[SmartIri, Seq[Future[CreateValueInNewResourceV2]]] = propertyIriStrs.map {
587+
propertyValueFuturesMap: Map[SmartIri, Seq[Future[CreateValueInNewResourceV2]]] = propertyIriStrs.map {
588588
propertyIriStr =>
589589
val propertyIri: SmartIri = propertyIriStr.toSmartIriWithErr(throw BadRequestException(s"Invalid property IRI: <$propertyIriStr>"))
590-
591590
val valuesArray: JsonLDArray = jsonLDDocument.requireArray(propertyIriStr)
592591

593-
val propertyValues = valuesArray.value.map {
592+
val valueFuturesSeq: Seq[Future[CreateValueInNewResourceV2]] = valuesArray.value.map {
594593
valueJsonLD =>
595594
val valueJsonLDObject = valueJsonLD match {
596595
case jsonLDObject: JsonLDObject => jsonLDObject
@@ -606,15 +605,22 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource
606605
settings = settings,
607606
log = log
608607
)
608+
609609
maybeCustomValueIri: Option[SmartIri] = valueJsonLDObject.maybeIDAsKnoraDataIri
610-
maybeCustomValueUUID: Option[UUID] = valueJsonLDObject.maybeUUID
610+
maybeCustomValueUUID: Option[UUID] = valueJsonLDObject.maybeUUID(OntologyConstants.KnoraApiV2Complex.ValueHasUUID)
611611

612-
// Get the values's creation date.
612+
// Get the value's creation date.
613+
// TODO: creationDate for values is a bug, and will not be supported in future. Use valueCreationDate instead.
613614
maybeCustomValueCreationDate: Option[Instant] = valueJsonLDObject.maybeDatatypeValueInObject(
615+
key = OntologyConstants.KnoraApiV2Complex.ValueCreationDate,
616+
expectedDatatype = OntologyConstants.Xsd.DateTimeStamp.toSmartIri,
617+
validationFun = stringFormatter.xsdDateTimeStampToInstant
618+
).orElse(valueJsonLDObject.maybeDatatypeValueInObject(
614619
key = OntologyConstants.KnoraApiV2Complex.CreationDate,
615620
expectedDatatype = OntologyConstants.Xsd.DateTimeStamp.toSmartIri,
616621
validationFun = stringFormatter.xsdDateTimeStampToInstant
617-
)
622+
))
623+
618624
maybePermissions: Option[String] = valueJsonLDObject.maybeStringWithValidation(OntologyConstants.KnoraApiV2Complex.HasPermissions, stringFormatter.toSparqlEncodedString)
619625
} yield CreateValueInNewResourceV2(
620626
valueContent = valueContent,
@@ -625,23 +631,22 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource
625631
)
626632
}
627633

628-
propertyIri -> propertyValues
634+
propertyIri -> valueFuturesSeq
629635
}.toMap
630636

631-
values: Map[SmartIri, Seq[CreateValueInNewResourceV2]] <- ActorUtil.sequenceSeqFuturesInMap(valueFutures)
637+
propertyValuesMap: Map[SmartIri, Seq[CreateValueInNewResourceV2]] <- ActorUtil.sequenceSeqFuturesInMap(propertyValueFuturesMap)
632638

633639
// Get information about the project that the resource should be created in.
634640
projectInfoResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM(
635641
ProjectIdentifierADM(maybeIri = Some(projectIri.toString)),
636642
requestingUser = requestingUser
637643
)).mapTo[ProjectGetResponseADM]
638-
639644
} yield CreateResourceRequestV2(
640645
createResource = CreateResourceV2(
641646
resourceIri = maybeCustomResourceIri,
642647
resourceClassIri = resourceClassIri,
643648
label = label,
644-
values = values,
649+
values = propertyValuesMap,
645650
projectADM = projectInfoResponse.project,
646651
permissions = permissions,
647652
creationDate = creationDate
@@ -751,12 +756,15 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update
751756
* @param resourceIri the IRI of the resource.
752757
* @param resourceClassIri the IRI of the resource class.
753758
* @param maybeDeleteComment a comment explaining why the resource is being marked as deleted.
759+
* @param maybeDeleteDate a timestamp indicating when the resource was marked as deleted. If not supplied,
760+
* the current time will be used.
754761
* @param maybeLastModificationDate the resource's last modification date, if any.
755762
* @param erase if `true`, the resource will be erased from the triplestore, otherwise it will be marked as deleted.
756763
*/
757764
case class DeleteOrEraseResourceRequestV2(resourceIri: IRI,
758765
resourceClassIri: SmartIri,
759766
maybeDeleteComment: Option[String] = None,
767+
maybeDeleteDate: Option[Instant] = None,
760768
maybeLastModificationDate: Option[Instant] = None,
761769
erase: Boolean = false,
762770
requestingUser: UserADM,
@@ -812,10 +820,17 @@ object DeleteOrEraseResourceRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteO
812820

813821
val maybeDeleteComment: Option[String] = jsonLDDocument.maybeStringWithValidation(OntologyConstants.KnoraApiV2Complex.DeleteComment, stringFormatter.toSparqlEncodedString)
814822

823+
val maybeDeleteDate: Option[Instant] = jsonLDDocument.maybeDatatypeValueInObject(
824+
key = OntologyConstants.KnoraApiV2Complex.DeleteDate,
825+
expectedDatatype = OntologyConstants.Xsd.DateTimeStamp.toSmartIri,
826+
validationFun = stringFormatter.xsdDateTimeStampToInstant
827+
)
828+
815829
DeleteOrEraseResourceRequestV2(
816830
resourceIri = resourceIri.toString,
817831
resourceClassIri = resourceClassIri,
818832
maybeDeleteComment = maybeDeleteComment,
833+
maybeDeleteDate = maybeDeleteDate,
819834
maybeLastModificationDate = maybeLastModificationDate,
820835
requestingUser = requestingUser,
821836
apiRequestID = apiRequestID

0 commit comments

Comments
 (0)