Repository: BlueBrain/nexus (scala)

Issue:
Nexus ship: map the projects in cross project resolvers
**Motivation**
Using the same mapping as used for mapping / changing the names of the projects being imported, map the projects defined in a cross project resolver.

Pull request description:
Fixes #4814

Patch:
diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessor.scala
index 9e3a7d83ae..8b432fe5e7 100644
--- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessor.scala
+++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessor.scala
@@ -15,7 +15,7 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
 import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig
 import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject
 import ch.epfl.bluebrain.nexus.delta.sourcing.model.{EntityType, Identity}
-import ch.epfl.bluebrain.nexus.ship.resolvers.ResolverProcessor.logger
+import ch.epfl.bluebrain.nexus.ship.resolvers.ResolverProcessor.{logger, patchValue}
 import ch.epfl.bluebrain.nexus.ship.{EventClock, EventProcessor, ImportStatus, ProjectMapper}
 import io.circe.Decoder
 
@@ -40,10 +40,12 @@ class ResolverProcessor private (resolvers: Resolvers, projectMapper: ProjectMap
     event match {
       case ResolverCreated(_, _, value, _, _, _, _) =>
         implicit val caller: Caller = Caller(s, identities(value))
-        resolvers.create(id, projectRef, value)
+        val patched                 = patchValue(value, projectMapper)
+        resolvers.create(id, projectRef, patched)
       case ResolverUpdated(_, _, value, _, _, _, _) =>
         implicit val caller: Caller = Caller(s, identities(value))
-        resolvers.update(id, projectRef, cRev, value)
+        val patched                 = patchValue(value, projectMapper)
+        resolvers.update(id, projectRef, cRev, patched)
       case _: ResolverTagAdded                      =>
         // Tags have been removed
         IO.unit
@@ -74,6 +76,14 @@ object ResolverProcessor {
 
   private val logger = Logger[ResolverProcessor]
 
+  def patchValue(value: ResolverValue, projectMapper: ProjectMapper): ResolverValue =
+    value match {
+      case ip: InProjectValue    => ip
+      case cp: CrossProjectValue =>
+        val mappedProjects = cp.projects.map(projectMapper.map)
+        cp.copy(projects = mappedProjects)
+    }
+
   def apply(
       fetchContext: FetchContext,
       projectMapper: ProjectMapper,


Test patch:
diff --git a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessorSuite.scala b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessorSuite.scala
new file mode 100644
index 0000000000..b283661537
--- /dev/null
+++ b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/resolvers/ResolverProcessorSuite.scala
@@ -0,0 +1,44 @@
+package ch.epfl.bluebrain.nexus.ship.resolvers
+
+import cats.data.NonEmptyList
+import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv
+import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverValue.{CrossProjectValue, InProjectValue}
+import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.{IdentityResolution, Priority}
+import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef
+import ch.epfl.bluebrain.nexus.ship.ProjectMapper
+import ch.epfl.bluebrain.nexus.testkit.mu.NexusSuite
+
+class ResolverProcessorSuite extends NexusSuite {
+
+  private val originalProject = ProjectRef.unsafe("bbp", "sscx")
+  private val targetProject   = ProjectRef.unsafe("obp", "somato")
+
+  private val projectMapper = ProjectMapper(Map(originalProject -> targetProject))
+
+  private val priority = Priority.unsafe(42)
+
+  test("Patching does not affect in project resolvers") {
+    val original = InProjectValue(priority)
+
+    val obtained = ResolverProcessor.patchValue(original, projectMapper)
+    assertEquals(obtained, original)
+  }
+
+  test("Patching a cross project resolver") {
+    val unpatchedProject = ProjectRef.unsafe("neurosciencegraph", "datamodels")
+    val originalProjects = NonEmptyList.of(unpatchedProject, originalProject)
+    val original         = CrossProjectValue(
+      Some("My resolver"),
+      Some("My description"),
+      priority,
+      Set(nxv + "Schema"),
+      originalProjects,
+      IdentityResolution.UseCurrentCaller
+    )
+
+    val expected = original.copy(projects = NonEmptyList.of(unpatchedProject, targetProject))
+    val obtained = ResolverProcessor.patchValue(original, projectMapper)
+    assertEquals(obtained, expected)
+  }
+
+}