Skip to content

Commit

Permalink
Add an endpoint to undeprecate resources (#4454)
Browse files Browse the repository at this point in the history
  • Loading branch information
olivergrabinski authored Nov 3, 2023
1 parent 3ed0219 commit b42f0a3
Show file tree
Hide file tree
Showing 22 changed files with 911 additions and 417 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ final class ResourcesRoutes(
}
)
},
// Undeprecate a resource
(pathPrefix("undeprecate") & put & parameter("rev".as[Int])) { rev =>
authorizeFor(ref, Write).apply {
emit(
resources
.undeprecate(id, ref, schemaOpt, rev)
.flatTap(indexUIO(ref, _, mode))
.map(_.void)
.attemptNarrow[ResourceRejection]
.rejectWhen(wrongJsonOrNotFound)
)
}
},
(pathPrefix("update-schema") & put & pathEndOrSingleSlash) {
authorizeFor(ref, Write).apply {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"@context": "https://bluebrain.github.io/nexus/contexts/error.json",
"@type": "ResourceIsNotDeprecated",
"reason": "Resource '{{id}}' is not deprecated."
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,13 @@ sealed trait EventMetric extends Product with Serializable {

object EventMetric {

val Created: Label = Label.unsafe("Created")
val Updated: Label = Label.unsafe("Updated")
val Refreshed: Label = Label.unsafe("Refreshed")
val Tagged: Label = Label.unsafe("Tagged")
val TagDeleted: Label = Label.unsafe("TagDeleted")
val Deprecated: Label = Label.unsafe("Deprecated")
val Created: Label = Label.unsafe("Created")
val Updated: Label = Label.unsafe("Updated")
val Refreshed: Label = Label.unsafe("Refreshed")
val Tagged: Label = Label.unsafe("Tagged")
val TagDeleted: Label = Label.unsafe("TagDeleted")
val Deprecated: Label = Label.unsafe("Deprecated")
val Undeprecated: Label = Label.unsafe("Undeprecated")

/**
* Metric extracted from an event independent from an org/project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.model._
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.{ApiMappings, ProjectBase, ProjectContext}
import ch.epfl.bluebrain.nexus.delta.sdk.resources.model.ResourceCommand._
import ch.epfl.bluebrain.nexus.delta.sdk.resources.model.ResourceEvent._
import ch.epfl.bluebrain.nexus.delta.sdk.resources.model.ResourceRejection.{IncorrectRev, InvalidResourceId, ResourceAlreadyExists, ResourceFetchRejection, ResourceIsDeprecated, ResourceNotFound, RevisionNotFound, TagNotFound, UnexpectedResourceSchema}
import ch.epfl.bluebrain.nexus.delta.sdk.resources.model.ResourceRejection.{IncorrectRev, InvalidResourceId, ResourceAlreadyExists, ResourceFetchRejection, ResourceIsDeprecated, ResourceIsNotDeprecated, ResourceNotFound, RevisionNotFound, TagNotFound, UnexpectedResourceSchema}
import ch.epfl.bluebrain.nexus.delta.sdk.resources.model.{ResourceCommand, ResourceEvent, ResourceRejection, ResourceState}
import ch.epfl.bluebrain.nexus.delta.sourcing.ScopedEntityDefinition.Tagger
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject
Expand Down Expand Up @@ -195,6 +195,26 @@ trait Resources {
rev: Int
)(implicit caller: Subject): IO[DataResource]

/**
* Undeprecates an existing resource.
*
* @param id
* the identifier that will be expanded to the Iri of the resource
* @param projectRef
* the project reference where the resource belongs
* @param schemaOpt
* the optional identifier that will be expanded to the schema reference of the resource. A None value uses the
* currently available resource schema reference.
* @param rev
* the revision of the resource
*/
def undeprecate(
id: IdSegment,
projectRef: ProjectRef,
schemaOpt: Option[IdSegment],
rev: Int
)(implicit caller: Subject): IO[DataResource]

/**
* Fetches a resource state.
*
Expand Down Expand Up @@ -315,13 +335,18 @@ object Resources {
_.copy(rev = e.rev, deprecated = true, updatedAt = e.instant, updatedBy = e.subject)
}

def undeprecated(e: ResourceUndeprecated): Option[ResourceState] = state.map {
_.copy(rev = e.rev, deprecated = false, updatedAt = e.instant, updatedBy = e.subject)
}

event match {
case e: ResourceCreated => created(e)
case e: ResourceUpdated => updated(e)
case e: ResourceRefreshed => refreshed(e)
case e: ResourceTagAdded => tagAdded(e)
case e: ResourceTagDeleted => tagDeleted(e)
case e: ResourceDeprecated => deprecated(e)
case e: ResourceUndeprecated => undeprecated(e)
case e: ResourceSchemaUpdated => resourceSchemaUpdated(e)
}
}
Expand Down Expand Up @@ -453,13 +478,22 @@ object Resources {
} yield ResourceDeprecated(c.id, c.project, s.types, s.rev + 1, time, c.subject)
}

def undeprecate(c: UndeprecateResource) =
for {
s <- stateWhereResourceExists(c)
_ <- raiseWhenDifferentSchema(c, s)
_ <- IO.raiseWhen(!s.deprecated)(ResourceIsNotDeprecated(c.id))
time <- IOInstant.now
} yield ResourceUndeprecated(c.id, c.project, s.types, s.rev + 1, time, c.subject)

cmd match {
case c: CreateResource => create(c)
case c: UpdateResource => update(c)
case c: RefreshResource => refresh(c)
case c: TagResource => tag(c)
case c: DeleteResourceTag => deleteTag(c)
case c: DeprecateResource => deprecate(c)
case c: UndeprecateResource => undeprecate(c)
case c: UpdateResourceSchema => updateResourceSchema(c)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,18 @@ final class ResourcesImpl private (
res <- eval(DeprecateResource(iri, projectRef, schemeRefOpt, rev, caller))
} yield res).span("deprecateResource")

override def undeprecate(
id: IdSegment,
projectRef: ProjectRef,
schemaOpt: Option[IdSegment],
rev: Int
)(implicit caller: Subject): IO[DataResource] =
(for {
(iri, projectContext) <- expandWithContext(fetchContext.onModify, projectRef, id)
schemaRefOpt <- IO.fromEither(expandResourceRef(schemaOpt, projectContext))
res <- eval(UndeprecateResource(iri, projectRef, schemaRefOpt, rev, caller))
} yield res).span("undeprecateResource")

def fetchState(
id: IdSegmentRef,
projectRef: ProjectRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,27 @@ object ResourceCommand {
subject: Subject
) extends ResourceCommand
with ModifyCommand

/**
* Command that signals the intent to undeprecate a resource.
*
* @param id
* the resource identifier
* @param project
* the project where the resource belongs
* @param schemaOpt
* the optional schema of the resource. A None value ignores the schema from this operation
* @param rev
* the last known revision of the resource
* @param subject
* the subject which created this event
*/
final case class UndeprecateResource(
id: Iri,
project: ProjectRef,
schemaOpt: Option[ResourceRef],
rev: Int,
subject: Subject
) extends ResourceCommand
with ModifyCommand
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,31 @@ object ResourceEvent {
subject: Subject
) extends ResourceEvent

/**
* Event representing a resource undeprecation.
*
* @param id
* the resource identifier
* @param project
* the project where the resource belongs
* @param types
* the collection of known resource types
* @param rev
* the resource revision
* @param instant
* the instant when this event was created
* @param subject
* the subject which created this event
*/
final case class ResourceUndeprecated(
id: Iri,
project: ProjectRef,
types: Set[Iri],
rev: Int,
instant: Instant,
subject: Subject
) extends ResourceEvent

@nowarn("cat=unused")
val serializer: Serializer[Iri, ResourceEvent] = {
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.CompactedJsonLd.Database._
Expand Down Expand Up @@ -316,6 +341,7 @@ object ResourceEvent {
case _: ResourceTagAdded => Tagged
case _: ResourceTagDeleted => TagDeleted
case _: ResourceDeprecated => Deprecated
case _: ResourceUndeprecated => Undeprecated
case _: ResourceSchemaUpdated => Updated
},
event.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ object ResourceRejection {
*/
final case class ResourceIsDeprecated(id: Iri) extends ResourceRejection(s"Resource '$id' is deprecated.")

/**
* Rejection returned when attempting to undeprecate a resource that is not deprecated
* @param id
* the resource identifier
*/
final case class ResourceIsNotDeprecated(id: Iri) extends ResourceRejection(s"Resource '$id' is not deprecated.")

/**
* Rejection returned when a subject intends to perform an operation on the current resource, but either provided an
* incorrect revision or a concurrent update won over this attempt.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "https://bluebrain.github.io/nexus/vocabulary/myId",
"project": "myorg/myproj",
"types": [
"https://neuroshapes.org/Morphology"
],
"rev": 5,
"instant": "1970-01-01T00:00:00Z",
"subject": {
"subject": "username",
"realm": "myrealm",
"@type": "User"
},
"@type": "ResourceUndeprecated"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
"@context": "https://bluebrain.github.io/nexus/contexts/metadata.json",
"@id": "{{id}}",
"@type": "https://bluebrain.github.io/nexus/vocabulary/Custom",
"address": null,
"bool": false,
"name": "Alex",
"number": 24,
"_constrainedBy": "https://bluebrain.github.io/nexus/schemas/unconstrained.json",
"_createdAt": "1970-01-01T00:00:00Z",
"_createdBy": "http://localhost/v1/anonymous",
"_deprecated": true,
"_createdBy": "http://localhost/v1/realms/wonderland/users/bob",
"_deprecated": false,
"_incoming": "{{self}}/incoming",
"_outgoing": "{{self}}/outgoing",
"_project": "http://localhost/v1/projects/myorg/myproject",
"_rev": 10,
"_rev": 1,
"_schemaProject": "http://localhost/v1/projects/myorg/myproject",
"_self": "{{self}}",
"_updatedAt": "1970-01-01T00:00:00Z",
"_updatedBy": "http://localhost/v1/anonymous"
"_updatedBy": "http://localhost/v1/realms/wonderland/users/bob"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"@context": "https://bluebrain.github.io/nexus/contexts/metadata.json",
"@type": "ResourceUndeprecated",
"_instant": "1970-01-01T00:00:00Z",
"_project": "http://localhost/v1/projects/myorg/myproj",
"_resourceId": "https://bluebrain.github.io/nexus/vocabulary/myId",
"_rev": 5,
"_subject": "http://localhost/v1/realms/myrealm/users/username",
"_types": [
"https://neuroshapes.org/Morphology"
]
}
Loading

0 comments on commit b42f0a3

Please sign in to comment.