Skip to content

Commit

Permalink
Migrate Organizations to Cats Effect (#4360)
Browse files Browse the repository at this point in the history
  • Loading branch information
shinyhappydan authored Oct 13, 2023
1 parent bd60ed2 commit 8c0366d
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ package ch.epfl.bluebrain.nexus.delta.routes
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{Directive1, Route}
import cats.effect.IO
import cats.implicits._
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.encoder.JsonLdEncoder
import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering
import ch.epfl.bluebrain.nexus.delta.routes.OrganizationsRoutes.OrganizationInput
import ch.epfl.bluebrain.nexus.delta.sdk.OrganizationResource
import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck
import ch.epfl.bluebrain.nexus.delta.sdk.ce.DeltaDirectives.{emit => emitCE}
import ch.epfl.bluebrain.nexus.delta.sdk.ce.DeltaDirectives._
import ch.epfl.bluebrain.nexus.delta.sdk.circe.CirceUnmarshalling
import ch.epfl.bluebrain.nexus.delta.sdk.directives.DeltaDirectives._
import ch.epfl.bluebrain.nexus.delta.sdk.directives.{AuthDirectives, DeltaSchemeDirectives}
import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities
import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller
import ch.epfl.bluebrain.nexus.delta.sdk.implicits._
import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri
import ch.epfl.bluebrain.nexus.delta.sdk.model.{BaseUri, ResourceF}
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams.OrganizationSearchParams
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults._
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.{PaginationConfig, SearchResults}
Expand All @@ -29,7 +29,6 @@ import io.circe.Decoder
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder
import kamon.instrumentation.akka.http.TracingDirectives.operationName
import monix.execution.Scheduler

import scala.annotation.nowarn

Expand All @@ -54,7 +53,6 @@ final class OrganizationsRoutes(
)(implicit
baseUri: BaseUri,
paginationConfig: PaginationConfig,
s: Scheduler,
cr: RemoteContextResolution,
ordering: JsonKeyOrdering
) extends AuthDirectives(identities, aclCheck)
Expand All @@ -76,6 +74,14 @@ final class OrganizationsRoutes(
)
}

private def emitMetadata(value: IO[OrganizationResource]) = {
emit(
value
.mapValue(_.metadata)
.attemptNarrow[OrganizationRejection]
)
}

def routes: Route =
baseUriPrefix(baseUri.prefix) {
pathPrefix("orgs") {
Expand All @@ -88,7 +94,12 @@ final class OrganizationsRoutes(
implicit val searchJsonLdEncoder: JsonLdEncoder[SearchResults[OrganizationResource]] =
searchResultsJsonLdEncoder(Organization.context, pagination, uri)

emit(organizations.list(pagination, params, order).widen[SearchResults[OrganizationResource]])
emit(
organizations
.list(pagination, params, order)
.widen[SearchResults[OrganizationResource]]
.attemptNarrow[OrganizationRejection]
)
}
},
(resolveOrg & pathEndOrSingleSlash) { id =>
Expand All @@ -99,7 +110,10 @@ final class OrganizationsRoutes(
authorizeFor(id, orgs.write).apply {
// Update organization
entity(as[OrganizationInput]) { case OrganizationInput(description) =>
emit(organizations.update(id, description, rev).mapValue(_.metadata))
emitMetadata(
organizations
.update(id, description, rev)
)
}
}
}
Expand All @@ -108,9 +122,9 @@ final class OrganizationsRoutes(
authorizeFor(id, orgs.read).apply {
parameter("rev".as[Int].?) {
case Some(rev) => // Fetch organization at specific revision
emit(organizations.fetchAt(id, rev).leftWiden[OrganizationRejection])
emit(organizations.fetchAt(id, rev).attemptNarrow[OrganizationRejection])
case None => // Fetch organization
emit(organizations.fetch(id).leftWiden[OrganizationRejection])
emit(organizations.fetch(id).attemptNarrow[OrganizationRejection])

}
}
Expand All @@ -120,12 +134,14 @@ final class OrganizationsRoutes(
concat(
parameter("rev".as[Int]) { rev =>
authorizeFor(id, orgs.write).apply {
emit(organizations.deprecate(id, rev).mapValue(_.metadata))
emitMetadata(
organizations.deprecate(id, rev)
)
}
},
parameter("prune".requiredValue(true)) { _ =>
authorizeFor(id, orgs.delete).apply {
emitCE(orgDeleter.delete(id).attemptNarrow[OrganizationRejection])
emit(orgDeleter.delete(id).attemptNarrow[OrganizationRejection])
}
}
)
Expand All @@ -138,7 +154,12 @@ final class OrganizationsRoutes(
(put & authorizeFor(label, orgs.create)) {
// Create organization
entity(as[OrganizationInput]) { case OrganizationInput(description) =>
emit(StatusCodes.Created, organizations.create(label, description).mapValue(_.metadata))
val response: IO[Either[OrganizationRejection, ResourceF[Organization.Metadata]]] =
organizations.create(label, description).mapValue(_.metadata).attemptNarrow[OrganizationRejection]
emit(
StatusCodes.Created,
response
)
}
}
}
Expand Down Expand Up @@ -171,7 +192,6 @@ object OrganizationsRoutes {
)(implicit
baseUri: BaseUri,
paginationConfig: PaginationConfig,
s: Scheduler,
cr: RemoteContextResolution,
ordering: JsonKeyOrdering
): Route =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ch.epfl.bluebrain.nexus.delta.routes

import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{MalformedRequestContentRejection, Route}
import cats.effect.IO
import cats.implicits._
import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.contexts
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.JsonLdContext.keywords
Expand All @@ -10,6 +11,7 @@ import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.encoder.JsonLdEncoder
import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering
import ch.epfl.bluebrain.nexus.delta.routes.PermissionsRoutes.PatchPermissions._
import ch.epfl.bluebrain.nexus.delta.routes.PermissionsRoutes._
import ch.epfl.bluebrain.nexus.delta.sdk.PermissionsResource
import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck
import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclAddress
import ch.epfl.bluebrain.nexus.delta.sdk.ce.DeltaDirectives._
Expand All @@ -20,7 +22,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.implicits._
import ch.epfl.bluebrain.nexus.delta.sdk.model.{BaseUri, ResourceF}
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions.{permissions => permissionsPerms}
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.{Permission, PermissionsRejection}
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder
import io.circe.syntax._
Expand Down Expand Up @@ -63,16 +65,16 @@ final class PermissionsRoutes(identities: Identities, permissions: Permissions,
get {
authorizeFor(AclAddress.Root, permissionsPerms.read).apply {
parameter("rev".as[Int].?) {
case Some(rev) => emit(permissions.fetchAt(rev))
case None => emit(permissions.fetch)
case Some(rev) => emitPermissions(permissions.fetchAt(rev))
case None => emitPermissions(permissions.fetch)
}
}
},
// Replace permissions
(put & parameter("rev" ? 0)) { rev =>
authorizeFor(AclAddress.Root, permissionsPerms.write).apply {
entity(as[PatchPermissions]) {
case Replace(set) => emit(permissions.replace(set, rev).map(_.void))
case Replace(set) => emitVoid(permissions.replace(set, rev))
case _ =>
reject(
malformedContent(s"Value for field '${keywords.tpe}' must be 'Replace' when using 'PUT'.")
Expand All @@ -84,8 +86,8 @@ final class PermissionsRoutes(identities: Identities, permissions: Permissions,
(patch & parameter("rev" ? 0)) { rev =>
authorizeFor(AclAddress.Root, permissionsPerms.write).apply {
entity(as[PatchPermissions]) {
case Append(set) => emit(permissions.append(set, rev).map(_.void))
case Subtract(set) => emit(permissions.subtract(set, rev).map(_.void))
case Append(set) => emitVoid(permissions.append(set, rev))
case Subtract(set) => emitVoid(permissions.subtract(set, rev))
case _ =>
reject(
malformedContent(
Expand All @@ -99,7 +101,7 @@ final class PermissionsRoutes(identities: Identities, permissions: Permissions,
delete {
authorizeFor(AclAddress.Root, permissionsPerms.write).apply {
parameter("rev".as[Int]) { rev =>
emit(permissions.delete(rev).map(_.void))
emitVoid(permissions.delete(rev))
}
}
}
Expand All @@ -111,6 +113,14 @@ final class PermissionsRoutes(identities: Identities, permissions: Permissions,
}
}

private def emitVoid(value: IO[PermissionsResource]) = {
emit(value.map(_.void).attemptNarrow[PermissionsRejection])
}

private def emitPermissions(value: IO[PermissionsResource]) = {
emit(value.attemptNarrow[PermissionsRejection])
}

private def malformedContent(field: String) =
MalformedRequestContentRejection(field, new IllegalArgumentException())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ package ch.epfl.bluebrain.nexus.delta.wiring

import ch.epfl.bluebrain.nexus.delta.Main.pluginsMaxPriority
import ch.epfl.bluebrain.nexus.delta.config.AppConfig
import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution
import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering
import ch.epfl.bluebrain.nexus.delta.routes.{ElemRoutes, EventsRoutes}
import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._
import ch.epfl.bluebrain.nexus.delta.sdk._
import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck
import ch.epfl.bluebrain.nexus.delta.sdk.directives.DeltaSchemeDirectives
import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities
import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.Organizations
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationRejection
import ch.epfl.bluebrain.nexus.delta.sdk.projects.Projects
import ch.epfl.bluebrain.nexus.delta.sdk.sse.{SseElemStream, SseEncoder, SseEventLog}
import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
Expand All @@ -36,7 +37,7 @@ object EventsModule extends ModuleDef {
toCatsIO(
SseEventLog(
sseEncoders,
organizations.fetch(_).void,
organizations.fetch(_).void.toBIO[OrganizationRejection],
projects.fetch(_).map { p => (p.value.organizationUuid, p.value.uuid) },
config.sse,
xas
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ch.epfl.bluebrain.nexus.delta.wiring

import cats.effect.Clock
import cats.effect.{Clock, ContextShift, IO}
import ch.epfl.bluebrain.nexus.delta.Main.pluginsMaxPriority
import ch.epfl.bluebrain.nexus.delta.config.AppConfig
import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF
Expand All @@ -14,13 +14,10 @@ import ch.epfl.bluebrain.nexus.delta.sdk.directives.DeltaSchemeDirectives
import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities
import ch.epfl.bluebrain.nexus.delta.sdk.model.{BaseUri, MetadataContextValue}
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationEvent
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.{Organizations, OrganizationsImpl}
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.{OrganizationDeleter, Organizations, OrganizationsImpl}
import ch.epfl.bluebrain.nexus.delta.sdk.sse.SseEncoder
import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
import izumi.distage.model.definition.{Id, ModuleDef}
import monix.bio.UIO
import monix.execution.Scheduler
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.OrganizationDeleter

/**
* Organizations module wiring config.
Expand All @@ -33,15 +30,16 @@ object OrganizationsModule extends ModuleDef {
(
config: AppConfig,
scopeInitializations: Set[ScopeInitialization],
clock: Clock[UIO],
clock: Clock[IO],
uuidF: UUIDF,
xas: Transactors
xas: Transactors,
contextShift: ContextShift[IO]
) =>
OrganizationsImpl(
scopeInitializations,
config.organizations,
xas
)(clock, uuidF)
)(clock, uuidF, contextShift)
}

make[OrganizationDeleter].from { (xas: Transactors) =>
Expand All @@ -56,14 +54,12 @@ object OrganizationsModule extends ModuleDef {
cfg: AppConfig,
aclCheck: AclCheck,
schemeDirectives: DeltaSchemeDirectives,
s: Scheduler,
cr: RemoteContextResolution @Id("aggregate"),
ordering: JsonKeyOrdering
) =>
new OrganizationsRoutes(identities, organizations, orgDeleter, aclCheck, schemeDirectives)(
cfg.http.baseUri,
cfg.organizations.pagination,
s,
cr,
ordering
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package ch.epfl.bluebrain.nexus.delta.wiring

import cats.effect.{Clock, IO}
import cats.implicits._
import ch.epfl.bluebrain.nexus.delta.Main.pluginsMaxPriority
import ch.epfl.bluebrain.nexus.delta.config.AppConfig
import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration.toMonixBIOOps
import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF
import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.contexts
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.{ContextValue, RemoteContextResolution}
Expand All @@ -19,10 +21,11 @@ import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount
import ch.epfl.bluebrain.nexus.delta.sdk.model._
import ch.epfl.bluebrain.nexus.delta.sdk.model.metrics.ScopedEventMetricEncoder
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.Organizations
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationRejection
import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext.ContextRejection
import ch.epfl.bluebrain.nexus.delta.sdk.projects._
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectRejection.WrappedOrganizationRejection
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.{ApiMappings, Project, ProjectEvent}
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.{ApiMappings, Project, ProjectEvent, ProjectRejection}
import ch.epfl.bluebrain.nexus.delta.sdk.provisioning.ProjectProvisioning
import ch.epfl.bluebrain.nexus.delta.sdk.quotas.Quotas
import ch.epfl.bluebrain.nexus.delta.sdk.sse.SseEncoder
Expand Down Expand Up @@ -61,7 +64,12 @@ object ProjectsModule extends ModuleDef {
) =>
IO.pure(
ProjectsImpl(
organizations.fetchActiveOrganization(_).mapError(WrappedOrganizationRejection),
organizations
.fetchActiveOrganization(_)
.adaptError { case e: OrganizationRejection =>
WrappedOrganizationRejection(e)
}
.toBIO[ProjectRejection],
ValidateProjectDeletion(xas, config.projects.deletion.enabled),
scopeInitializations,
mappings.merge,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label
import ch.epfl.bluebrain.nexus.testkit.bio.IOFromMap
import io.circe.Json
import cats.effect.IO
import ch.epfl.bluebrain.nexus.testkit.ce.{CatsIOValues, IOFixedClock}

import java.util.UUID

class OrganizationsRoutesSpec extends BaseRouteSpec with IOFromMap {
class OrganizationsRoutesSpec extends BaseRouteSpec with IOFromMap with IOFixedClock with CatsIOValues {

private val fixedUuid = UUID.randomUUID()
implicit private val uuidF: UUIDF = UUIDF.fixed(fixedUuid)
Expand Down
Loading

0 comments on commit 8c0366d

Please sign in to comment.