From b36db37453f506c20fbd76dc2c4f533621132928 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:58:43 +0100 Subject: [PATCH] Wire initial remote context / resolver context resolution for schemas to work --- .../bluebrain/nexus/ship/ContextWiring.scala | 46 +++++++++++++++++++ .../epfl/bluebrain/nexus/ship/RunShip.scala | 3 +- .../nexus/ship/schemas/SchemaProcessor.scala | 5 +- .../nexus/ship/schemas/SchemaWiring.scala | 11 +++-- .../bluebrain/nexus/ship/EndToEndTest.scala | 44 ++++++++++++++++++ 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/ContextWiring.scala diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/ContextWiring.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/ContextWiring.scala new file mode 100644 index 0000000000..12b36e86c2 --- /dev/null +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/ContextWiring.scala @@ -0,0 +1,46 @@ +package ch.epfl.bluebrain.nexus.ship + +import cats.effect.{Clock, IO} +import ch.epfl.bluebrain.nexus.delta.kernel.utils.ClasspathResourceLoader +import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.contexts +import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi +import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.{ContextValue, RemoteContextResolution} +import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck +import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext +import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.ResolverContextResolution +import ch.epfl.bluebrain.nexus.delta.sdk.resources.FetchResource +import ch.epfl.bluebrain.nexus.delta.sdk.resources.Resources.ResourceLog +import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors +import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig +import ch.epfl.bluebrain.nexus.ship.acls.AclWiring +import ch.epfl.bluebrain.nexus.ship.resolvers.ResolverWiring + +object ContextWiring { + + implicit private val loader: ClasspathResourceLoader = ClasspathResourceLoader.withContext(getClass) + + def remoteContextResolution: IO[RemoteContextResolution] = + for { + shaclCtx <- ContextValue.fromFile("contexts/shacl.json") + schemasMetaCtx <- ContextValue.fromFile("contexts/schemas-metadata.json") + } yield RemoteContextResolution.fixed( + contexts.shacl -> shaclCtx, + contexts.schemasMetadata -> schemasMetaCtx + ) + + def resolverContextResolution( + resourceLog: Clock[IO] => IO[ResourceLog], + fetchContext: FetchContext, + config: EventLogConfig, + xas: Transactors + )(implicit jsonLdApi: JsonLdApi): Clock[IO] => IO[ResolverContextResolution] = { clock => + val aclCheck = AclCheck(AclWiring.acls(config, clock, xas)) + val resolvers = ResolverWiring.resolvers(fetchContext, config, clock, xas) + + for { + fetchResource <- resourceLog(clock).map(FetchResource(_)) + rcr <- remoteContextResolution + } yield ResolverContextResolution(aclCheck, resolvers, rcr, fetchResource) + } + +} diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala index 146c31f90f..51bf10c80f 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala @@ -53,10 +53,11 @@ class RunShip { eventLogConfig, xas ) + rcr = ContextWiring.resolverContextResolution(resourceLog, fetchContext, eventLogConfig, xas) // Processors projectProcessor <- ProjectProcessor(fetchActiveOrg, eventLogConfig, xas)(baseUri) resolverProcessor <- ResolverProcessor(fetchContext, eventLogConfig, xas) - schemaProcessor <- SchemaProcessor(schemaLog, fetchContext, schemaImports) + schemaProcessor <- SchemaProcessor(schemaLog, fetchContext, schemaImports, rcr) resourceProcessor <- ResourceProcessor(resourceLog, fetchContext) report <- EventProcessor .run(events, projectProcessor, resolverProcessor, schemaProcessor, resourceProcessor) diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaProcessor.scala index 6eed701711..aaa119db73 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaProcessor.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaProcessor.scala @@ -74,10 +74,11 @@ object SchemaProcessor { def apply( log: Clock[IO] => IO[SchemaLog], fetchContext: FetchContext, - schemaImports: Clock[IO] => IO[SchemaImports] + schemaImports: Clock[IO] => IO[SchemaImports], + resolverContextResolution: Clock[IO] => IO[ResolverContextResolution] )(implicit jsonLdApi: JsonLdApi): IO[SchemaProcessor] = EventClock.init().flatMap { clock => - val rcr = ResolverContextResolution.never for { + rcr <- resolverContextResolution(clock) schemaLog <- log(clock) imports <- schemaImports(clock) schemas = SchemasImpl(schemaLog, fetchContext, imports, rcr)(jsonLdApi, FailingUUID) diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaWiring.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaWiring.scala index 2f361b38b5..26017c0bd2 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaWiring.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/schemas/SchemaWiring.scala @@ -2,7 +2,6 @@ package ch.epfl.bluebrain.nexus.ship.schemas import cats.effect.{Clock, IO} import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi -import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution import ch.epfl.bluebrain.nexus.delta.rdf.shacl.ShaclShapesGraph import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext @@ -12,6 +11,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.schemas.Schemas.SchemaLog import ch.epfl.bluebrain.nexus.delta.sdk.schemas.{FetchSchema, SchemaImports, Schemas, ValidateSchema} import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig import ch.epfl.bluebrain.nexus.delta.sourcing.{ScopedEventLog, Transactors} +import ch.epfl.bluebrain.nexus.ship.ContextWiring import ch.epfl.bluebrain.nexus.ship.acls.AclWiring import ch.epfl.bluebrain.nexus.ship.resolvers.ResolverWiring @@ -34,10 +34,11 @@ object SchemaWiring { } yield SchemaImports(aclCheck, resolvers, fetchSchema, fetchResource) } - private def validateSchema(implicit api: JsonLdApi): IO[ValidateSchema] = { - val rcr = RemoteContextResolution.never - ShaclShapesGraph.shaclShaclShapes.map(ValidateSchema(api, _, rcr)) - } + private def validateSchema(implicit api: JsonLdApi): IO[ValidateSchema] = + for { + rcr <- ContextWiring.remoteContextResolution + shapesGraph <- ShaclShapesGraph.shaclShaclShapes + } yield ValidateSchema(api, shapesGraph, rcr) def schemaLog(config: EventLogConfig, xas: Transactors, api: JsonLdApi): Clock[IO] => IO[SchemaLog] = clock => diff --git a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/EndToEndTest.scala b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/EndToEndTest.scala index 1b0f033af5..90cf49733c 100644 --- a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/EndToEndTest.scala +++ b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/EndToEndTest.scala @@ -73,6 +73,19 @@ class EndToEndTest extends BaseIntegrationSpec { thereShouldBeAResource(project, resource, resourceJson) } + "transfer a schema" in { + val (project, _) = thereIsAProject() + val (schema, schemaJson) = thereIsASchema(project) + + whenTheExportIsRunOnProject(project) + theOldProjectIsDeleted(project) + + weRunTheImporter(project) + weFixThePermissions(project) + + thereShouldBeASchema(project, schema, schemaJson) + } + def thereIsAProject(): (ProjectRef, Json) = { val project: ProjectRef = ProjectRef.unsafe(genString(), genString()) createProjects(writer, project.organization.value, project.project.value).accepted @@ -187,6 +200,37 @@ class EndToEndTest extends BaseIntegrationSpec { } .accepted } + + def thereIsASchema(project: ProjectRef): (Iri, Json) = { + val schema = nxv + genString() + val encodedSchema = UrlUtils.encode(schema.toString) + // TODO: Review the json of the simpleSchema + val simpleSchema = + json"""{"shapes":[{"@id":"http://example.com/MyShape","@type":"http://www.w3.org/ns/shacl#NodeShape","nodeKind":"http://www.w3.org/ns/shacl#BlankNodeOrIRI","targetClass":"http://example.com/Custom","property":[{"path":"http://example.com/name","datatype":"http://www.w3.org/2001/XMLSchema#string","minCount":1}]}]}""" + deltaClient + .put[Json](s"/schemas/${project.organization}/${project.project}/$encodedSchema", simpleSchema, writer) { + (_, response) => + response.status shouldEqual StatusCodes.Created + } + .accepted + val (resourceJson, status) = deltaClient + .getJsonAndStatus(s"/schemas/${project.organization}/${project.project}/$encodedSchema", writer) + .accepted + status shouldEqual StatusCodes.OK + schema -> resourceJson + } + + def thereShouldBeASchema(project: ProjectRef, schema: Iri, originalJson: Json): Assertion = { + val encodedIri = UrlUtils.encode(schema.toString) + deltaClient + .get[Json](s"/schemas/${project.organization}/${project.project}/$encodedIri", writer) { (json, response) => + { + response.status shouldEqual StatusCodes.OK + json shouldEqual originalJson + } + } + .accepted + } } }