diff --git a/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ProcessApiServiceImpl.scala b/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ProcessApiServiceImpl.scala index c836690e..f55958e8 100644 --- a/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ProcessApiServiceImpl.scala +++ b/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ProcessApiServiceImpl.scala @@ -394,11 +394,21 @@ final case class ProcessApiServiceImpl( logger.info(operationLabel) val result: Future[EServiceDoc] = for { - eServiceUuid <- eServiceId.toFutureUUID - descriptorUuid <- descriptorId.toFutureUUID - documentIdUuid <- documentId.toFutureUUID - eServiceDoc <- catalogManagementService.getEServiceDocument(eServiceUuid, descriptorUuid, documentIdUuid) - } yield eServiceDoc.toApi + organizationId <- getOrganizationIdFutureUUID(contexts) + eServiceUuid <- eServiceId.toFutureUUID + descriptorUuid <- descriptorId.toFutureUUID + documentIdUuid <- documentId.toFutureUUID + role <- getUserRolesFuture(contexts) + (catalogItem, catalogDocument) <- catalogManagementService.getEServiceDocument( + eServiceUuid, + descriptorUuid, + documentIdUuid + ) + eService <- applyVisibilityToEService(catalogItem, organizationId, role) + _ <- + if (eService.descriptors.map(_.id).contains(descriptorUuid)) Future.successful(()) + else Future.failed(DescriptorDocumentNotFound(eServiceId, descriptorId, documentId)) + } yield catalogDocument.toApi onComplete(result) { getEServiceDocumentByIdResponse[EServiceDoc](operationLabel)(getEServiceDocumentById200) diff --git a/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ResponseHandlers.scala b/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ResponseHandlers.scala index 37ac357d..20218c99 100644 --- a/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ResponseHandlers.scala +++ b/src/main/scala/it/pagopa/interop/catalogprocess/api/impl/ResponseHandlers.scala @@ -240,6 +240,7 @@ object ResponseHandlers extends AkkaResponses { )(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route = result match { case Success(s) => success(s) + case Failure(ex: EServiceNotFound) => notFound(ex, logMessage) case Failure(ex: DescriptorDocumentNotFound) => notFound(ex, logMessage) case Failure(ex: ContentTypeParsingError) => badRequest(ex, logMessage) case Failure(ex) => internalServerError(ex, logMessage) diff --git a/src/main/scala/it/pagopa/interop/catalogprocess/service/CatalogManagementService.scala b/src/main/scala/it/pagopa/interop/catalogprocess/service/CatalogManagementService.scala index bf2de26e..9d9a1b0b 100644 --- a/src/main/scala/it/pagopa/interop/catalogprocess/service/CatalogManagementService.scala +++ b/src/main/scala/it/pagopa/interop/catalogprocess/service/CatalogManagementService.scala @@ -46,7 +46,7 @@ trait CatalogManagementService { def getEServiceDocument(eServiceId: UUID, descriptorId: UUID, documentId: UUID)(implicit ec: ExecutionContext, readModel: ReadModelService - ): Future[CatalogDocument] + ): Future[(CatalogItem, CatalogDocument)] def updateEServiceDocument( eServiceId: String, descriptorId: String, diff --git a/src/main/scala/it/pagopa/interop/catalogprocess/service/impl/CatalogManagementServiceImpl.scala b/src/main/scala/it/pagopa/interop/catalogprocess/service/impl/CatalogManagementServiceImpl.scala index e85b4767..a634b452 100644 --- a/src/main/scala/it/pagopa/interop/catalogprocess/service/impl/CatalogManagementServiceImpl.scala +++ b/src/main/scala/it/pagopa/interop/catalogprocess/service/impl/CatalogManagementServiceImpl.scala @@ -244,14 +244,14 @@ final case class CatalogManagementServiceImpl(invoker: CatalogManagementInvoker, override def getEServiceDocument(eServiceId: UUID, descriptorId: UUID, documentId: UUID)(implicit ec: ExecutionContext, readModel: ReadModelService - ): Future[CatalogDocument] = for { + ): Future[(CatalogItem, CatalogDocument)] = for { catalogItem <- ReadModelCatalogQueries .getEServiceDocument(eServiceId, descriptorId, documentId) .flatMap(_.toFuture(DescriptorDocumentNotFound(eServiceId.toString, descriptorId.toString, documentId.toString))) catalogDocument <- getDocument(catalogItem, descriptorId, documentId).toFuture( DescriptorDocumentNotFound(eServiceId.toString, descriptorId.toString, documentId.toString) ) - } yield catalogDocument + } yield (catalogItem, catalogDocument) override def getConsumers(eServiceId: UUID, offset: Int, limit: Int)(implicit ec: ExecutionContext, diff --git a/src/test/scala/it/pagopa/interop/catalogprocess/CatalogProcessSpec.scala b/src/test/scala/it/pagopa/interop/catalogprocess/CatalogProcessSpec.scala index bad20324..20c9382f 100644 --- a/src/test/scala/it/pagopa/interop/catalogprocess/CatalogProcessSpec.scala +++ b/src/test/scala/it/pagopa/interop/catalogprocess/CatalogProcessSpec.scala @@ -3065,26 +3065,27 @@ class CatalogProcessSpec extends SpecHelper with AnyWordSpecLike with ScalatestR } } "Document retrieve" should { - "succeed" in { + "succeed if role is admin and the requester is the producer" in { + val requesterId = UUID.randomUUID() val descriptorId = UUID.randomUUID() val documentId = UUID.randomUUID() implicit val context: Seq[(String, String)] = - Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> UUID.randomUUID().toString) + Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> requesterId.toString) val descriptor = SpecData.catalogDescriptor.copy( id = descriptorId, interface = Some(SpecData.catalogDocument.copy(id = documentId)) ) - val eService = SpecData.catalogItem.copy(descriptors = Seq(descriptor)) + val eService = SpecData.catalogItem.copy(producerId = requesterId, descriptors = Seq(descriptor)) (mockCatalogManagementService .getEServiceDocument(_: UUID, _: UUID, _: UUID)(_: ExecutionContext, _: ReadModelService)) .expects(SpecData.catalogItem.id, descriptorId, documentId, *, *) .once() - .returns(Future.successful(SpecData.catalogDocument.copy(id = documentId))) + .returns(Future.successful((eService, SpecData.catalogDocument.copy(id = documentId)))) Post() ~> service.getEServiceDocumentById( eService.id.toString, @@ -3094,6 +3095,67 @@ class CatalogProcessSpec extends SpecHelper with AnyWordSpecLike with ScalatestR status shouldEqual StatusCodes.OK } } + "succeed if role is api and the requester is the producer" in { + + val requesterId = UUID.randomUUID() + val descriptorId = UUID.randomUUID() + val documentId = UUID.randomUUID() + + implicit val context: Seq[(String, String)] = + Seq("bearer" -> bearerToken, USER_ROLES -> "api", ORGANIZATION_ID_CLAIM -> requesterId.toString) + + val descriptor = SpecData.catalogDescriptor.copy( + id = descriptorId, + interface = Some(SpecData.catalogDocument.copy(id = documentId)) + ) + + val eService = SpecData.catalogItem.copy(producerId = requesterId, descriptors = Seq(descriptor)) + + (mockCatalogManagementService + .getEServiceDocument(_: UUID, _: UUID, _: UUID)(_: ExecutionContext, _: ReadModelService)) + .expects(SpecData.catalogItem.id, descriptorId, documentId, *, *) + .once() + .returns(Future.successful((eService, SpecData.catalogDocument.copy(id = documentId)))) + + Post() ~> service.getEServiceDocumentById( + eService.id.toString, + descriptorId.toString, + documentId.toString + ) ~> check { + status shouldEqual StatusCodes.OK + } + } + "fail if the requester is not the producer and document belongs to a draft descriptor " in { + + val requesterId = UUID.randomUUID() + val descriptorId = UUID.randomUUID() + val documentId = UUID.randomUUID() + + implicit val context: Seq[(String, String)] = + Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> UUID.randomUUID().toString) + + val descriptor = SpecData.catalogDescriptor.copy( + id = descriptorId, + state = Draft, + interface = Some(SpecData.catalogDocument.copy(id = documentId)) + ) + + val eService = SpecData.catalogItem.copy(producerId = requesterId, descriptors = Seq(descriptor)) + + (mockCatalogManagementService + .getEServiceDocument(_: UUID, _: UUID, _: UUID)(_: ExecutionContext, _: ReadModelService)) + .expects(SpecData.catalogItem.id, descriptorId, documentId, *, *) + .once() + .returns(Future.successful((eService, SpecData.catalogDocument.copy(id = documentId)))) + + Post() ~> service.getEServiceDocumentById( + eService.id.toString, + descriptorId.toString, + documentId.toString + ) ~> check { + status shouldEqual StatusCodes.NotFound + } + } "fail if Document does not exist" in { val descriptorId = UUID.randomUUID() diff --git a/src/test/scala/it/pagopa/interop/catalogprocess/util/FakeDependencies.scala b/src/test/scala/it/pagopa/interop/catalogprocess/util/FakeDependencies.scala index 155918e0..e73292ad 100644 --- a/src/test/scala/it/pagopa/interop/catalogprocess/util/FakeDependencies.scala +++ b/src/test/scala/it/pagopa/interop/catalogprocess/util/FakeDependencies.scala @@ -26,6 +26,7 @@ import it.pagopa.interop.catalogmanagement.model.{ CatalogAttributes, CatalogDocument, Published, + CatalogDescriptor, CatalogDescriptorState, CatalogItemMode, Deliver @@ -44,6 +45,7 @@ import it.pagopa.interop.attributeregistrymanagement.model.persistence.attribute import java.time.OffsetDateTime import java.util.UUID import scala.concurrent.{ExecutionContext, Future} +import it.pagopa.interop.catalogmanagement.model.Automatic /** * Holds fake implementation of dependencies for tests not requiring neither mocks or stubs @@ -73,15 +75,50 @@ object FakeDependencies { override def getEServiceDocument(eServiceId: UUID, descriptorId: UUID, documentId: UUID)(implicit ec: ExecutionContext, readModel: ReadModelService - ): Future[CatalogDocument] = Future.successful( - CatalogDocument( - id = UUID.randomUUID(), - name = "fake", - contentType = "fake", - prettyName = "fake", - path = "fake", - checksum = "fake", - uploadDate = OffsetDateTime.now() + ): Future[(CatalogItem, CatalogDocument)] = Future.successful( + ( + CatalogItem( + id = UUID.randomUUID(), + producerId = UUID.randomUUID(), + name = "fake", + description = "fake", + technology = Rest, + descriptors = Seq( + CatalogDescriptor( + id = UUID.randomUUID(), + version = "???", + description = None, + audience = Seq.empty, + voucherLifespan = 0, + dailyCallsPerConsumer = 0, + dailyCallsTotal = 0, + interface = None, + docs = Seq.empty, + state = Published, + agreementApprovalPolicy = Some(Automatic), + serverUrls = Nil, + attributes = CatalogAttributes(Nil, Nil, Nil), + createdAt = OffsetDateTime.now(), + publishedAt = Some(OffsetDateTime.now()), + suspendedAt = None, + deprecatedAt = None, + archivedAt = None + ) + ), + attributes = Some(CatalogAttributes.empty), + createdAt = OffsetDateTime.now(), + riskAnalysis = Seq.empty, + mode = Deliver + ), + CatalogDocument( + id = UUID.randomUUID(), + name = "fake", + contentType = "fake", + prettyName = "fake", + path = "fake", + checksum = "fake", + uploadDate = OffsetDateTime.now() + ) ) )