@@ -385,8 +385,16 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
385385 s " Resource < ${resource.resourceIri}> is not a member of class < ${updateResourceMetadataRequestV2.resourceClassIri}> " )
386386 }
387387
388+ // If resource has already been modified, make sure that its lastModificationDate is given in the request body.
389+ _ = if (resource.lastModificationDate.nonEmpty && updateResourceMetadataRequestV2.maybeLastModificationDate.isEmpty) {
390+ throw EditConflictException (
391+ s " Resource < ${resource.resourceIri}> has been modified in the past. Its lastModificationDate " +
392+ s " ${resource.lastModificationDate.get} must be included in the request body. " )
393+ }
394+
388395 // Make sure that the resource hasn't been updated since the client got its last modification date.
389- _ = if (resource.lastModificationDate != updateResourceMetadataRequestV2.maybeLastModificationDate) {
396+ _ = if (updateResourceMetadataRequestV2.maybeLastModificationDate.nonEmpty &&
397+ resource.lastModificationDate != updateResourceMetadataRequestV2.maybeLastModificationDate) {
390398 throw EditConflictException (s " Resource < ${resource.resourceIri}> has been modified since you last read it " )
391399 }
392400
@@ -2491,7 +2499,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
24912499 def getResourceHistoryEvents (
24922500 resourceFullHistRequest : ResourceFullHistoryGetRequestV2 ): Future [Seq [ResourceAndValueHistoryV2 ]] = {
24932501
2494- val resourceHist = resourceFullHistRequest.resourceVersionHistory.reverse
2502+ val resourceHist : Seq [ ResourceHistoryEntry ] = resourceFullHistRequest.resourceVersionHistory.reverse
24952503 // Collect the full representations of the resource for each version date
24962504 val histories : Seq [Future [(ResourceHistoryEntry , ReadResourceV2 )]] = resourceHist.map { hist =>
24972505 for {
@@ -2508,8 +2516,8 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
25082516
25092517 // Create an event for the resource at creation time
25102518 (creationTimeHist, resourceAtCreation) = fullReps.head
2511- resourceCreateEvent : ResourceAndValueHistoryV2 = getResourceAtCreationDate (resourceAtCreation, creationTimeHist)
2512- resourceCreationEvent : Seq [ ResourceAndValueHistoryV2 ] = Seq (resourceCreateEvent )
2519+ resourceCreationEvent : Seq [ ResourceAndValueHistoryV2 ] = getResourceCreationEvent (resourceAtCreation,
2520+ creationTimeHist )
25132521
25142522 // If there is a version history for deletion of the event, create a delete resource event for it.
25152523 (deletionRep, resourceAtValueChanges) = fullReps.tail.partition {
@@ -2519,14 +2527,19 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
25192527 .deletionInfo
25202528 .exists(deletionInfo => deletionInfo.deleteDate == resHist.versionDate)
25212529 }
2522- resourceDeleteEvent = getResourceAtDeletionDates (deletionRep)
2530+ resourceDeleteEvent = getResourceDeletionEvents (deletionRep)
25232531
25242532 // For each value version, form an event
25252533 valuesEvents : Seq [ResourceAndValueHistoryV2 ] = resourceAtValueChanges.flatMap {
2526- case (versionHist, readResource) => getValueAtGivenVersionDate (readResource, versionHist, fullReps)
2534+ case (versionHist, readResource) => getValueEvents (readResource, versionHist, fullReps)
25272535 }
25282536
2529- } yield resourceCreationEvent ++ resourceDeleteEvent ++ valuesEvents
2537+ // Get the update resource metadata event, if there is any.
2538+ resourceMetadataUpdateEvent : Seq [ResourceAndValueHistoryV2 ] = getResourceMetadataUpdateEvent(fullReps.last,
2539+ valuesEvents,
2540+ resourceDeleteEvent)
2541+
2542+ } yield resourceCreationEvent ++ resourceDeleteEvent ++ valuesEvents ++ resourceMetadataUpdateEvent
25302543 }
25312544
25322545 /**
@@ -2562,8 +2575,8 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
25622575 * @param versionInfoAtCreation the history info of the version; i.e. versionDate and author.
25632576 * @return a createResource event.
25642577 */
2565- private def getResourceAtCreationDate (resourceAtTimeOfCreation : ReadResourceV2 ,
2566- versionInfoAtCreation : ResourceHistoryEntry ): ResourceAndValueHistoryV2 = {
2578+ private def getResourceCreationEvent (resourceAtTimeOfCreation : ReadResourceV2 ,
2579+ versionInfoAtCreation : ResourceHistoryEntry ): Seq [ ResourceAndValueHistoryV2 ] = {
25672580
25682581 val requestBody : ResourceEventBody = ResourceEventBody (
25692582 resourceIri = resourceAtTimeOfCreation.resourceIri,
@@ -2577,12 +2590,13 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
25772590 creationDate = Some (resourceAtTimeOfCreation.creationDate)
25782591 )
25792592
2580- ResourceAndValueHistoryV2 (
2581- eventType = ResourceAndValueEventsUtil .CREATE_RESOURCE_EVENT ,
2582- versionDate = versionInfoAtCreation.versionDate,
2583- author = versionInfoAtCreation.author,
2584- eventBody = requestBody
2585- )
2593+ Seq (
2594+ ResourceAndValueHistoryV2 (
2595+ eventType = ResourceAndValueEventsUtil .CREATE_RESOURCE_EVENT ,
2596+ versionDate = versionInfoAtCreation.versionDate,
2597+ author = versionInfoAtCreation.author,
2598+ eventBody = requestBody
2599+ ))
25862600 }
25872601
25882602 /**
@@ -2592,7 +2606,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
25922606 * the full representation of resource at time of deletion.
25932607 * @return a seq of deleteResource events.
25942608 */
2595- private def getResourceAtDeletionDates (
2609+ private def getResourceDeletionEvents (
25962610 resourceDeletionInfo : Seq [(ResourceHistoryEntry , ReadResourceV2 )]): Seq [ResourceAndValueHistoryV2 ] = {
25972611 resourceDeletionInfo.map {
25982612 case (delHist, fullRepresentation) =>
@@ -2620,7 +2634,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
26202634 * @param allResourceVersions all full representations of resource for each version date in its history.
26212635 * @return a create/update/delete value event.
26222636 */
2623- private def getValueAtGivenVersionDate (
2637+ private def getValueEvents (
26242638 resourceAtGivenTime : ReadResourceV2 ,
26252639 versionHist : ResourceHistoryEntry ,
26262640 allResourceVersions : Seq [(ResourceHistoryEntry , ReadResourceV2 )]): Seq [ResourceAndValueHistoryV2 ] = {
@@ -2693,7 +2707,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
26932707 } else {
26942708 // No. return updateValue event
26952709 val (updateEventType : String , updateEventRequestBody : ValueEventBody ) =
2696- getUpdateEventType (propIri, readValue, allResourceVersions, resourceAtGivenTime)
2710+ getValueUpdateEventType (propIri, readValue, allResourceVersions, resourceAtGivenTime)
26972711 ResourceAndValueHistoryV2 (
26982712 eventType = updateEventType,
26992713 versionDate = versionHist.versionDate,
@@ -2719,10 +2733,10 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
27192733 * @param resourceAtGivenTime the full representation of the resource at time of value update.
27202734 * @return (eventType, update event request body)
27212735 */
2722- private def getUpdateEventType (propertyIri : SmartIri ,
2723- currentVersionOfValue : ReadValueV2 ,
2724- allResourceVersions : Seq [(ResourceHistoryEntry , ReadResourceV2 )],
2725- resourceAtGivenTime : ReadResourceV2 ): (String , ValueEventBody ) = {
2736+ private def getValueUpdateEventType (propertyIri : SmartIri ,
2737+ currentVersionOfValue : ReadValueV2 ,
2738+ allResourceVersions : Seq [(ResourceHistoryEntry , ReadResourceV2 )],
2739+ resourceAtGivenTime : ReadResourceV2 ): (String , ValueEventBody ) = {
27262740 val previousValueIri : IRI = currentVersionOfValue.previousValueIri.getOrElse(
27272741 throw BadRequestException (" No previous value IRI found for the value, Please report this as a bug." ))
27282742
@@ -2777,4 +2791,88 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
27772791 }
27782792 event
27792793 }
2794+
2795+ /**
2796+ * Returns an updateResourceMetadata event as [[ResourceAndValueHistoryV2 ]] with request body of the form
2797+ * [[ResourceMetadataEventBody ]] with information necessary to make update metadata of resource request with a
2798+ * given modification date.
2799+ *
2800+ * @param latestVersionOfResource the full representation of the resource.
2801+ * @param valueEvents the events describing value operations.
2802+ * @param resourceDeleteEvents the events describing resource deletion operations.
2803+ * @return an updateResourceMetadata event.
2804+ */
2805+ private def getResourceMetadataUpdateEvent (
2806+ latestVersionOfResource : (ResourceHistoryEntry , ReadResourceV2 ),
2807+ valueEvents : Seq [ResourceAndValueHistoryV2 ],
2808+ resourceDeleteEvents : Seq [ResourceAndValueHistoryV2 ]): Seq [ResourceAndValueHistoryV2 ] = {
2809+ val readResource : ReadResourceV2 = latestVersionOfResource._2
2810+ val author : IRI = latestVersionOfResource._1.author
2811+ // Is lastModificationDate of resource None
2812+ readResource.lastModificationDate match {
2813+ // Yes. Do nothing.
2814+ case None => Seq .empty[ResourceAndValueHistoryV2 ]
2815+ // No. Either a value or the resource metadata must have been modified.
2816+ case Some (modDate) =>
2817+ val deletionEventWithSameDate = resourceDeleteEvents.find(event => event.versionDate == modDate)
2818+ // Is the lastModificationDate of the resource the same as its deletion date?
2819+ val updateMetadataEvent = if (deletionEventWithSameDate.isDefined) {
2820+ // Yes. Do noting.
2821+ Seq .empty[ResourceAndValueHistoryV2 ]
2822+ // No. Is there any value event?
2823+ } else if (valueEvents.isEmpty) {
2824+ // No. After creation of the resource its metadata must have been updated, use creation date as the lastModification date of the event.
2825+ val requestBody = ResourceMetadataEventBody (
2826+ resourceIri = readResource.resourceIri,
2827+ resourceClassIri = readResource.resourceClassIri,
2828+ lastModificationDate = readResource.creationDate,
2829+ newModificationDate = modDate
2830+ )
2831+ val event = ResourceAndValueHistoryV2 (
2832+ eventType = ResourceAndValueEventsUtil .UPDATE_RESOURCE_METADATA_EVENT ,
2833+ versionDate = modDate,
2834+ author = author,
2835+ eventBody = requestBody
2836+ )
2837+ Seq (event)
2838+ } else {
2839+ // Yes. Sort the value events by version date.
2840+ val sortedEvents = valueEvents.sortBy(_.versionDate)
2841+ // Is there any value event with version date equal to lastModificationDate of the resource?
2842+ val modDateExists = valueEvents.find(event => event.versionDate == modDate)
2843+ modDateExists match {
2844+ // Yes. The last modification date of the resource reflects the modification of a value. Return nothing.
2845+ case Some (_) => Seq .empty[ResourceAndValueHistoryV2 ]
2846+ // No. The last modification date of the resource reflects update of a resource's metadata. Return an updateMetadataEvent
2847+ case None =>
2848+ // Find the event with version date before resource's last modification date.
2849+ val eventsBeforeModDate = sortedEvents.filter(event => event.versionDate.isBefore(modDate))
2850+ // Is there any value with versionDate before this date?
2851+ val oldModDate = if (eventsBeforeModDate.nonEmpty) {
2852+ // Yes. assign the versionDate of the last value event as lastModificationDate for request.
2853+ eventsBeforeModDate.last.versionDate
2854+
2855+ } else {
2856+ // No. The metadata of the resource must have been updated after the value operations, use the version date
2857+ // of the last value event as the lastModificationDate
2858+ sortedEvents.last.versionDate
2859+ }
2860+ val requestBody = ResourceMetadataEventBody (
2861+ resourceIri = readResource.resourceIri,
2862+ resourceClassIri = readResource.resourceClassIri,
2863+ lastModificationDate = oldModDate,
2864+ newModificationDate = modDate
2865+ )
2866+ val event = ResourceAndValueHistoryV2 (
2867+ eventType = ResourceAndValueEventsUtil .UPDATE_RESOURCE_METADATA_EVENT ,
2868+ versionDate = modDate,
2869+ author = author,
2870+ eventBody = requestBody
2871+ )
2872+ Seq (event)
2873+ }
2874+ }
2875+ updateMetadataEvent
2876+ }
2877+ }
27802878}
0 commit comments