Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ 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.marshalling.{HttpResponseFields, OriginalSource, RdfMarshalling}
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults.searchResultsJsonLdEncoder
import ch.epfl.bluebrain.nexus.delta.sdk.model.{BaseUri, IdSegment, IdSegmentRef, ResourceF}
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions.resolvers.{read => Read, write => Write}
Expand All @@ -40,16 +42,13 @@ import io.circe.Json
* the resolvers module
* @param schemeDirectives
* directives related to orgs and projects
* @param indexAction
* the indexing action on write operations
*/
final class ResolversRoutes(
identities: Identities,
aclCheck: AclCheck,
resolvers: Resolvers,
multiResolution: MultiResolution,
schemeDirectives: DeltaSchemeDirectives,
indexAction: IndexingAction.Execute[Resolver]
schemeDirectives: DeltaSchemeDirectives
)(implicit
baseUri: BaseUri,
cr: RemoteContextResolution,
Expand Down Expand Up @@ -86,17 +85,22 @@ final class ResolversRoutes(
(baseUriPrefix(baseUri.prefix) & replaceUri("resolvers", schemas.resolvers)) {
pathPrefix("resolvers") {
extractCaller { implicit caller =>
(projectRef & indexingMode) { (project, indexingMode) =>
def index(resolver: ResolverResource): IO[Unit] =
indexAction(resolver.value.project, resolver, indexingMode)
val authorizeRead = authorizeFor(project, Read)
val authorizeWrite = authorizeFor(project, Write)
projectRef { project =>
val authorizeRead = authorizeFor(project, Read)
val authorizeWrite = authorizeFor(project, Write)
concat(
pathEndOrSingleSlash {
(get & authorizeRead) {
implicit val searchJsonLdEncoder: JsonLdEncoder[SearchResults[ResolverResource]] =
searchResultsJsonLdEncoder(Resolver.context)
emit(resolvers.list(project).widen[SearchResults[ResolverResource]])
}
},
pathEndOrSingleSlash {
// Create a resolver without an id segment
(post & noParameter("rev") & entity(as[Json])) { payload =>
authorizeWrite {
emitMetadata(Created, resolvers.create(project, payload).flatTap(index))
emitMetadata(Created, resolvers.create(project, payload))
}
}
},
Expand All @@ -109,17 +113,17 @@ final class ResolversRoutes(
(parameter("rev".as[Int].?) & pathEndOrSingleSlash & entity(as[Json])) {
case (None, payload) =>
// Create a resolver with an id segment
emitMetadata(Created, resolvers.create(resolver, project, payload).flatTap(index))
emitMetadata(Created, resolvers.create(resolver, project, payload))
case (Some(rev), payload) =>
// Update a resolver
emitMetadata(resolvers.update(resolver, project, rev, payload).flatTap(index))
emitMetadata(resolvers.update(resolver, project, rev, payload))
}
}
},
(delete & parameter("rev".as[Int])) { rev =>
authorizeWrite {
// Deprecate a resolver
emitMetadataOrReject(resolvers.deprecate(resolver, project, rev).flatTap(index))
emitMetadataOrReject(resolvers.deprecate(resolver, project, rev))
}
},
// Fetches a resolver
Expand Down Expand Up @@ -226,14 +230,13 @@ object ResolversRoutes {
aclCheck: AclCheck,
resolvers: Resolvers,
multiResolution: MultiResolution,
schemeDirectives: DeltaSchemeDirectives,
index: IndexingAction.Execute[Resolver]
schemeDirectives: DeltaSchemeDirectives
)(implicit
baseUri: BaseUri,
cr: RemoteContextResolution,
ordering: JsonKeyOrdering,
fusionConfig: FusionConfig
): Route =
new ResolversRoutes(identities, aclCheck, resolvers, multiResolution, schemeDirectives, index).routes
new ResolversRoutes(identities, aclCheck, resolvers, multiResolution, schemeDirectives).routes

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@ import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.contexts
import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.{ContextValue, RemoteContextResolution}
import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering
import ch.epfl.bluebrain.nexus.delta.routes.ResolversRoutes
import ch.epfl.bluebrain.nexus.delta.sdk.IndexingAction.AggregateIndexingAction
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.fusion.FusionConfig
import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities
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.projects.FetchContext
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ApiMappings
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers._
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.{Resolver, ResolverEvent}
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverEvent
import ch.epfl.bluebrain.nexus.delta.sdk.sse.SseEncoder
import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
import izumi.distage.model.definition.{Id, ModuleDef}
Expand Down Expand Up @@ -70,8 +68,6 @@ object ResolversModule extends ModuleDef {
aclCheck: AclCheck,
resolvers: Resolvers,
schemeDirectives: DeltaSchemeDirectives,
indexingAction: AggregateIndexingAction,
shift: Resolver.Shift,
multiResolution: MultiResolution,
baseUri: BaseUri,
cr: RemoteContextResolution @Id("aggregate"),
Expand All @@ -83,8 +79,7 @@ object ResolversModule extends ModuleDef {
aclCheck,
resolvers,
multiResolution,
schemeDirectives,
indexingAction(_, _, _)(shift)
schemeDirectives
)(
baseUri,
cr,
Expand All @@ -95,17 +90,13 @@ object ResolversModule extends ModuleDef {

many[SseEncoder[_]].add { base: BaseUri => ResolverEvent.sseEncoder(base) }

many[ScopedEventMetricEncoder[_]].add { ResolverEvent.resolverEventMetricEncoder }

make[ResolverScopeInitialization].from { (resolvers: Resolvers, serviceAccount: ServiceAccount, config: AppConfig) =>
ResolverScopeInitialization(resolvers, serviceAccount, config.resolvers.defaults)
}
many[ScopeInitialization].ref[ResolverScopeInitialization]

many[ApiMappings].add(Resolvers.mappings)

many[ResourceToSchemaMappings].add(Resolvers.resourcesToSchemas)

many[MetadataContextValue].addEffect(MetadataContextValue.fromFile("contexts/resolvers-metadata.json"))

many[RemoteContextResolution].addEffect(
Expand All @@ -120,10 +111,4 @@ object ResolversModule extends ModuleDef {
many[PriorityRoute].add { (route: ResolversRoutes) =>
PriorityRoute(pluginsMaxPriority + 9, route.routes, requiresStrictEntity = true)
}

make[Resolver.Shift].from { (resolvers: Resolvers, base: BaseUri) =>
Resolver.shift(resolvers)(base)
}

many[ResourceShift[_, _, _]].ref[Resolver.Shift]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import cats.effect.IO
import ch.epfl.bluebrain.nexus.delta.kernel.utils.{UUIDF, UrlUtils}
import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri
import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.{contexts, nxv, schema, schemas}
import ch.epfl.bluebrain.nexus.delta.sdk.IndexingAction
import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclSimpleCheck
import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclAddress
import ch.epfl.bluebrain.nexus.delta.sdk.directives.DeltaSchemeDirectives
Expand Down Expand Up @@ -121,9 +120,7 @@ class ResolversRoutesSpec extends BaseRouteSpec {
private lazy val multiResolution = MultiResolution(fetchContext, resolverResolution)

private lazy val routes =
Route.seal(
ResolversRoutes(identities, aclCheck, resolvers, multiResolution, groupDirectives, IndexingAction.noop)
)
Route.seal(ResolversRoutes(identities, aclCheck, resolvers, multiResolution, groupDirectives))

private def withId(id: String, payload: Json) =
payload.deepMerge(Json.obj("@id" -> id.asJson))
Expand Down Expand Up @@ -573,6 +570,21 @@ class ResolversRoutesSpec extends BaseRouteSpec {
}
}

"listing resolvers" should {
"succeed if the user has read access to the given project" in {
Get(s"/v1/resolvers/${project.ref}") ~> asBob ~> routes ~> check {
status shouldEqual StatusCodes.OK
response.asJson.asObject.value("_total").value shouldEqual Json.fromLong(3L)
}
}

"fail if the user has no read access to the given project" in {
Get(s"/v1/resolvers/${project.ref}") ~> routes ~> check {
response.shouldBeForbidden
}
}
}

val idResourceEncoded = UrlUtils.encode(resourceId.toString)
val idSchemaEncoded = UrlUtils.encode(schemaId.toString)
val unknownResourceEncoded = UrlUtils.encode((nxv + "xxx").toString)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import ch.epfl.bluebrain.nexus.delta.sdk.model.ResourceF
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization
import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project
import ch.epfl.bluebrain.nexus.delta.sdk.realms.model.Realm
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.Resolver
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject
import ch.epfl.bluebrain.nexus.delta.sourcing.model.ResourceRef.Latest
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef, ResourceRef}
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ResourceRef}

/**
* Enumeration of the possible Search Parameters
Expand Down Expand Up @@ -156,38 +155,4 @@ object SearchParams {
)
}

/**
* Search parameters for resolvers
*
* @param project
* the option project of the resolver resources
* @param deprecated
* the optional deprecation status of resolver project resources
* @param rev
* the optional revision of the resolver resources
* @param createdBy
* the optional subject who created the resolver resource
* @param updatedBy
* the optional subject who updated the resolver
* @param types
* the types the resolver should contain
* @param filter
* the additional filter to select resolvers
*/
final case class ResolverSearchParams(
project: Option[ProjectRef] = None,
deprecated: Option[Boolean] = None,
rev: Option[Int] = None,
createdBy: Option[Subject] = None,
updatedBy: Option[Subject] = None,
types: Set[Iri] = Set(nxv.Resolver),
filter: Resolver => IO[Boolean]
) extends SearchParams[Resolver] {
override val schema: Option[ResourceRef] = Some(Latest(nxvschemas.resolvers))

override def matches(resource: ResourceF[Resolver]): IO[Boolean] =
super.matches(resource).map(_ && project.forall(_ == resource.value.project))

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package ch.epfl.bluebrain.nexus.delta.sdk.resolvers

import cats.effect.IO
import cats.implicits._
import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination
import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri
import ch.epfl.bluebrain.nexus.delta.sdk.ResourceShifts
import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck
import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller
import ch.epfl.bluebrain.nexus.delta.sdk.jsonld.JsonLdContent
import ch.epfl.bluebrain.nexus.delta.sdk.model.Fetch.Fetch
import ch.epfl.bluebrain.nexus.delta.sdk.model.ResourceF
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.ResultEntry
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams.ResolverSearchParams
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.ResolverResolution.{DeprecationCheck, ResolverResolutionResult}
Expand All @@ -19,10 +17,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.Resolver.{CrossProjectR
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverResolutionRejection._
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResourceResolutionReport.{ResolverFailedReport, ResolverReport, ResolverSuccessReport}
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.{Resolver, ResolverRejection, ResolverResolutionRejection, ResourceResolutionReport}
import ch.epfl.bluebrain.nexus.delta.sdk.{ResolverResource, ResourceShifts}
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, ProjectRef, ResourceRef}

import java.time.Instant
import scala.collection.immutable.VectorMap

/**
Expand Down Expand Up @@ -229,10 +225,6 @@ object ResolverResolution {

type ResolverResolutionResult[R] = (ResolverReport, Option[R])

private val resolverSearchParams = ResolverSearchParams(deprecated = Some(false), filter = _ => IO.pure(true))

private val resolverOrdering: Ordering[ResolverResource] = Ordering[Instant] on (r => r.createdAt)

/**
* Allows to check and exclude deprecated resources from the resolution
* @param enabled
Expand Down Expand Up @@ -264,17 +256,21 @@ object ResolverResolution {
extractTypes: R => Set[Iri],
readPermission: Permission,
deprecationCheck: DeprecationCheck[R]
) = new ResolverResolution(
checkAcls = (p: ProjectRef, identities: Set[Identity]) => aclCheck.authorizeFor(p, readPermission, identities),
listResolvers = (projectRef: ProjectRef) =>
resolvers
.list(projectRef, Pagination.OnePage, resolverSearchParams, resolverOrdering)
.map { r => r.results.map { r: ResultEntry[ResolverResource] => r.source.value }.toList },
fetchResolver = (id: Iri, projectRef: ProjectRef) => resolvers.fetchActiveResolver(id, projectRef),
fetch = fetch,
extractTypes,
deprecationCheck
)
) = {
def fetchActiveResolvers(project: ProjectRef) = resolvers
.list(project)
.map { r =>
r.results.mapFilter { r => Option.unless(r.source.deprecated)(r.source.value) }.toList
}
new ResolverResolution(
checkAcls = (p: ProjectRef, identities: Set[Identity]) => aclCheck.authorizeFor(p, readPermission, identities),
listResolvers = fetchActiveResolvers,
fetchResolver = (id: Iri, projectRef: ProjectRef) => resolvers.fetchActiveResolver(id, projectRef),
fetch = fetch,
extractTypes,
deprecationCheck
)
}

/**
* Resolution based on resolvers and reference exchanges
Expand Down
Loading