From d14720e1d568f95e2c6f7c4f97a4d0b1d70ff4cf Mon Sep 17 00:00:00 2001 From: Riccardo Torsoli <122275960+nttdata-rtorsoli@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:41:22 +0100 Subject: [PATCH] PIN-4220 tenant-process: Added Mail Id (#81) Co-authored-by: nttdata-rtorsoli --- .../resources/interface-specification.yml | 148 +++++++++++++----- .../api/adapters/AdaptableSeed.scala | 6 +- .../api/adapters/ApiAdapters.scala | 38 ++--- .../adapters/ReadModelTenantAdapters.scala | 28 +++- .../adapters/TenantManagementAdapters.scala | 21 ++- .../api/impl/TenantApiMarshallerImpl.scala | 8 +- .../api/impl/TenantApiServiceImpl.scala | 95 +++++------ .../tenantprocess/api/impl/package.scala | 11 +- .../error/ResponseHandlers.scala | 30 ++-- .../service/TenantManagementService.scala | 4 + .../impl/TenantManagementServiceImpl.scala | 24 +++ src/test/resources/authz.json | 16 ++ .../authz/TenantApiServiceAuthzSpec.scala | 15 +- .../provider/TenantCreationSpec.scala | 54 +++++-- .../provider/TenantUpdateSpec.scala | 88 ++++------- .../utils/FakeDependencies.scala | 14 +- .../tenantprocess/utils/SpecData.scala | 51 ++++-- .../tenantprocess/utils/SpecHelper.scala | 14 ++ 18 files changed, 447 insertions(+), 218 deletions(-) diff --git a/src/main/resources/interface-specification.yml b/src/main/resources/interface-specification.yml index c02ebff..e15a9bb 100644 --- a/src/main/resources/interface-specification.yml +++ b/src/main/resources/interface-specification.yml @@ -221,7 +221,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Tenant' + $ref: '#/components/schemas/ResourceId' '409': description: Selfcare Id is already assigned and is different from the request content: @@ -410,30 +410,6 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/Problem' - post: - tags: - - tenant - operationId: updateTenant - description: Updates the tenant - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TenantDelta' - responses: - '200': - description: Tenant updated - content: - application/json: - schema: - $ref: '#/components/schemas/Tenant' - '404': - description: Tenant Not Found - content: - application/problem+json: - schema: - $ref: '#/components/schemas/Problem' /tenants/origin/{origin}/code/{code}: parameters: - $ref: '#/components/parameters/CorrelationIdHeader' @@ -705,6 +681,84 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/Problem' + /tenants/{tenantId}/mails: + parameters: + - $ref: '#/components/parameters/CorrelationIdHeader' + - name: tenantId + in: path + description: the tenant id + required: true + schema: + type: string + format: uuid + post: + tags: + - tenant + summary: Add a tenant mail + operationId: addTenantMail + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MailSeed' + responses: + '204': + description: Tenant Mail Added + '400': + description: Invalid input + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' + '403': + description: Forbidden + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' + '404': + description: Tenant not found + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' + /tenants/{tenantId}/mails/{mailId}: + parameters: + - $ref: '#/components/parameters/CorrelationIdHeader' + - name: tenantId + in: path + description: the tenant id + required: true + schema: + type: string + format: uuid + - name: mailId + in: path + description: the mail id + required: true + schema: + type: string + delete: + tags: + - tenant + summary: Delete a tenant mail + operationId: deleteTenantMail + responses: + '204': + description: Tenant Mail Deleted + '403': + description: Forbidden + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' + '404': + description: Tenant not found + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' /status: get: security: [] @@ -763,6 +817,15 @@ components: maxLength: 64 required: - code + ResourceId: + description: Modified resource id + type: object + properties: + id: + type: string + format: uuid + required: + - id Tenant: description: Tenant model type: object @@ -795,7 +858,12 @@ components: name: type: string kind: - $ref: '#/components/schemas/TenantKind' + $ref: '#/components/schemas/TenantKind' + onboardedAt: + type: string + format: date-time + subUnitType: + $ref: '#/components/schemas/TenantUnitType' required: - id - certifier @@ -1014,20 +1082,24 @@ components: type: string minLength: 1 maxLength: 1000 + digitalAddress: + $ref: '#/components/schemas/MailSeed' + onboardedAt: + type: string + format: date-time + subUnitType: + $ref: '#/components/schemas/TenantUnitType' required: - externalId - selfcareId - name - TenantDelta: - description: Tenant Delta model - type: object - properties: - mails: - type: array - items: - $ref: '#/components/schemas/MailSeed' - required: - - mails + - onboardedAt + - subUnitType + TenantUnitType: + type: string + enum: + - AOO + - UO MailSeed: description: A specific kind of mail type: object @@ -1049,6 +1121,8 @@ components: description: A specific kind of mail type: object properties: + id: + type: string kind: $ref: '#/components/schemas/MailKind' address: @@ -1061,6 +1135,7 @@ components: type: string maxLength: 250 required: + - id - kind - address - createdAt @@ -1068,6 +1143,7 @@ components: type: string enum: - CONTACT_EMAIL + - DIGITAL_ADDRESS Problem: properties: type: diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/AdaptableSeed.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/AdaptableSeed.scala index d79871b..f65d718 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/AdaptableSeed.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/AdaptableSeed.scala @@ -1,7 +1,7 @@ package it.pagopa.interop.tenantprocess.api.adapters import it.pagopa.interop.tenantmanagement.client.model.{TenantAttribute, TenantSeed, TenantKind} -import it.pagopa.interop.tenantprocess.api.adapters.ApiAdapters.ExternalIdWrapper +import it.pagopa.interop.tenantprocess.api.adapters.ApiAdapters._ import it.pagopa.interop.tenantprocess.model.{InternalTenantSeed, M2MTenantSeed, SelfcareTenantSeed} import java.util.UUID @@ -58,7 +58,9 @@ object AdaptableSeed { features = Nil, attributes = attributes, name = a.name, - kind = kind + kind = kind, + onboardedAt = Some(a.onboardedAt), + subUnitType = Some(a.subUnitType.toDependency) ) } } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ApiAdapters.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ApiAdapters.scala index b55ffb4..b7de2a9 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ApiAdapters.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ApiAdapters.scala @@ -2,7 +2,7 @@ package it.pagopa.interop.tenantprocess.api.adapters import cats.syntax.all._ import it.pagopa.interop.tenantmanagement.model.tenant.PersistentExternalId -import it.pagopa.interop.tenantmanagement.client.model.MailKind.CONTACT_EMAIL +import it.pagopa.interop.tenantmanagement.client.model.MailKind.{DIGITAL_ADDRESS, CONTACT_EMAIL} import it.pagopa.interop.tenantmanagement.client.model.{ Certifier => DependencyCertifier, DeclaredTenantAttribute => DependencyDeclaredTenantAttribute, @@ -10,24 +10,20 @@ import it.pagopa.interop.tenantmanagement.client.model.{ MailKind => DependencyMailKind, MailSeed => DependencyMailSeed, TenantAttribute => DependencyTenantAttribute, - TenantDelta => DependencyTenantDelta, TenantFeature => DependencyTenantFeature, TenantKind => DependencyTenantKind, TenantVerifier => DependencyTenantVerifier, - VerifiedTenantAttribute => DependencyVerifiedTenantAttribute + VerifiedTenantAttribute => DependencyVerifiedTenantAttribute, + TenantUnitType => DependencyTenantUnitType } import it.pagopa.interop.tenantprocess.model._ +import it.pagopa.interop.commons.utils.Digester.toSha256 import java.time.OffsetDateTime import java.util.UUID object ApiAdapters { - implicit class MailWrapper(private val m: Mail) extends AnyVal { - def fromAPI: DependencyMailSeed = - DependencyMailSeed(kind = m.kind.fromAPI, address = m.address, description = m.description) - } - implicit class TenantKindWrapper(private val tk: TenantKind) extends AnyVal { def fromAPI: DependencyTenantKind = tk match { case TenantKind.PA => DependencyTenantKind.PA @@ -38,7 +34,8 @@ object ApiAdapters { implicit class MailKindWrapper(private val mk: MailKind) extends AnyVal { def fromAPI: DependencyMailKind = mk match { - case MailKind.CONTACT_EMAIL => CONTACT_EMAIL + case MailKind.CONTACT_EMAIL => CONTACT_EMAIL + case MailKind.DIGITAL_ADDRESS => DIGITAL_ADDRESS } } @@ -50,18 +47,14 @@ object ApiAdapters { def fromAPI: DependencyCertifier = DependencyCertifier(c.certifierId) } - implicit class TenantDeltaWrapper(private val td: TenantDelta) extends AnyVal { - def fromAPI( - selfcareId: Option[String], - features: Seq[DependencyTenantFeature], - kind: DependencyTenantKind - ): DependencyTenantDelta = - DependencyTenantDelta(selfcareId, features, mails = td.mails.map(_.toDependency), kind) - } - implicit class MailSeedWrapper(private val ms: MailSeed) extends AnyVal { def toDependency: DependencyMailSeed = - DependencyMailSeed(kind = ms.kind.fromAPI, address = ms.address, description = ms.description) + DependencyMailSeed( + id = toSha256(ms.address.getBytes()), + kind = ms.kind.fromAPI, + address = ms.address, + description = ms.description + ) } implicit class ExternalIdWrapper(private val id: ExternalId) extends AnyVal { @@ -78,6 +71,13 @@ object ApiAdapters { ) } + implicit class TenantUnitTypeWrapper(private val u: TenantUnitType) extends AnyVal { + def toDependency: DependencyTenantUnitType = u match { + case TenantUnitType.AOO => DependencyTenantUnitType.AOO + case TenantUnitType.UO => DependencyTenantUnitType.UO + } + } + implicit class VerifiedTenantAttributeSeedWrapper(private val seed: VerifiedTenantAttributeSeed) extends AnyVal { def toCreateDependency(now: OffsetDateTime, requesterId: UUID): DependencyTenantAttribute = DependencyTenantAttribute( diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ReadModelTenantAdapters.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ReadModelTenantAdapters.scala index 6465e9d..0e69f92 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ReadModelTenantAdapters.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/ReadModelTenantAdapters.scala @@ -20,7 +20,9 @@ object ReadModelTenantAdapters extends SprayJsonSupport with DefaultJsonProtocol attributes = t.attributes.map(_.toApi), createdAt = t.createdAt, updatedAt = t.updatedAt, - mails = t.mails.map(_.toApi) + onboardedAt = t.onboardedAt, + mails = t.mails.map(_.toApi), + subUnitType = t.subUnitType.map(_.toApi) ) def toManagement: Management.Tenant = Management.Tenant( id = t.id, @@ -32,14 +34,17 @@ object ReadModelTenantAdapters extends SprayJsonSupport with DefaultJsonProtocol attributes = t.attributes.map(_.toManagement), createdAt = t.createdAt, updatedAt = t.updatedAt, - mails = t.mails.map(_.toManagement) + onboardedAt = t.onboardedAt, + mails = t.mails.map(_.toManagement), + subUnitType = t.subUnitType.map(_.toManagement) ) } implicit class PersistentMailWrapper(private val m: PersistentTenantMail) extends AnyVal { def toApi: Mail = - Mail(kind = m.kind.toApi, address = m.address, createdAt = m.createdAt, description = m.description) + Mail(id = m.id, kind = m.kind.toApi, address = m.address, createdAt = m.createdAt, description = m.description) def toManagement: Management.Mail = Management.Mail( + id = m.id, kind = m.kind.toManagement, address = m.address, createdAt = m.createdAt, @@ -49,10 +54,23 @@ object ReadModelTenantAdapters extends SprayJsonSupport with DefaultJsonProtocol implicit class PersistentMailKindWrapper(private val k: PersistentTenantMailKind) extends AnyVal { def toApi: MailKind = k match { - case PersistentTenantMailKind.ContactEmail => MailKind.CONTACT_EMAIL + case PersistentTenantMailKind.ContactEmail => MailKind.CONTACT_EMAIL + case PersistentTenantMailKind.DigitalAddress => MailKind.DIGITAL_ADDRESS } def toManagement: Management.MailKind = k match { - case PersistentTenantMailKind.ContactEmail => Management.MailKind.CONTACT_EMAIL + case PersistentTenantMailKind.ContactEmail => Management.MailKind.CONTACT_EMAIL + case PersistentTenantMailKind.DigitalAddress => Management.MailKind.DIGITAL_ADDRESS + } + } + + implicit class PersistentTenantUnitTypeWrapper(private val u: PersistentTenantUnitType) extends AnyVal { + def toApi: TenantUnitType = u match { + case PersistentTenantUnitType.Aoo => TenantUnitType.AOO + case PersistentTenantUnitType.Uo => TenantUnitType.UO + } + def toManagement: Management.TenantUnitType = u match { + case PersistentTenantUnitType.Aoo => Management.TenantUnitType.AOO + case PersistentTenantUnitType.Uo => Management.TenantUnitType.UO } } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/TenantManagementAdapters.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/TenantManagementAdapters.scala index 65f7da2..124bbf2 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/TenantManagementAdapters.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/adapters/TenantManagementAdapters.scala @@ -15,7 +15,8 @@ import it.pagopa.interop.tenantmanagement.client.model.{ TenantKind => DependencyTenantKind, TenantRevoker => DependencyTenantRevoker, TenantVerifier => DependencyTenantVerifier, - VerifiedTenantAttribute => DependencyVerifiedTenantAttribute + VerifiedTenantAttribute => DependencyVerifiedTenantAttribute, + TenantUnitType => DependencyTenantUnitType } import it.pagopa.interop.agreementprocess.client.{model => AgreementDependency} import it.pagopa.interop.tenantprocess.model._ @@ -34,7 +35,9 @@ object TenantManagementAdapters extends SprayJsonSupport with DefaultJsonProtoco updatedAt = t.updatedAt, mails = t.mails.map(_.toApi), name = t.name, - kind = t.kind.map(_.toApi) + kind = t.kind.map(_.toApi), + onboardedAt = t.onboardedAt, + subUnitType = t.subUnitType.map(_.toApi) ) } @@ -47,13 +50,21 @@ object TenantManagementAdapters extends SprayJsonSupport with DefaultJsonProtoco } implicit class DependencyMailWrapper(private val m: DependencyMail) extends AnyVal { - def toApi: Mail = Mail(kind = m.kind.toApi, address = m.address, createdAt = m.createdAt) - def toSeed: DependencyMailSeed = DependencyMailSeed(m.kind, m.address, m.description) + def toApi: Mail = Mail(id = m.id, kind = m.kind.toApi, address = m.address, createdAt = m.createdAt) + def toSeed: DependencyMailSeed = DependencyMailSeed(m.id, m.kind, m.address, m.description) } implicit class DependencyMailKindWrapper(private val k: DependencyMailKind) extends AnyVal { def toApi: MailKind = k match { - case DependencyMailKind.CONTACT_EMAIL => MailKind.CONTACT_EMAIL + case DependencyMailKind.CONTACT_EMAIL => MailKind.CONTACT_EMAIL + case DependencyMailKind.DIGITAL_ADDRESS => MailKind.DIGITAL_ADDRESS + } + } + + implicit class DependencyTenantUnitTypeWrapper(private val u: DependencyTenantUnitType) extends AnyVal { + def toApi: TenantUnitType = u match { + case DependencyTenantUnitType.AOO => TenantUnitType.AOO + case DependencyTenantUnitType.UO => TenantUnitType.UO } } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiMarshallerImpl.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiMarshallerImpl.scala index dcd07f4..eb39a40 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiMarshallerImpl.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiMarshallerImpl.scala @@ -9,9 +9,6 @@ import spray.json._ object TenantApiMarshallerImpl extends TenantApiMarshaller with SprayJsonSupport with DefaultJsonProtocol { - override implicit def fromEntityUnmarshallerTenantDelta: FromEntityUnmarshaller[TenantDelta] = - sprayJsonUnmarshaller[TenantDelta] - override implicit def toEntityMarshallerProblem: ToEntityMarshaller[Problem] = entityMarshallerProblem override implicit def toEntityMarshallerTenant: ToEntityMarshaller[Tenant] = sprayJsonMarshaller[Tenant] @@ -39,4 +36,9 @@ object TenantApiMarshallerImpl extends TenantApiMarshaller with SprayJsonSupport : FromEntityUnmarshaller[UpdateVerifiedTenantAttributeSeed] = sprayJsonUnmarshaller[UpdateVerifiedTenantAttributeSeed] + override implicit def fromEntityUnmarshallerMailSeed: FromEntityUnmarshaller[MailSeed] = + sprayJsonUnmarshaller[MailSeed] + + override implicit def toEntityMarshallerResourceId: ToEntityMarshaller[ResourceId] = + sprayJsonMarshaller[ResourceId] } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiServiceImpl.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiServiceImpl.scala index 70c65c6..7c6ecf7 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiServiceImpl.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/TenantApiServiceImpl.scala @@ -118,32 +118,6 @@ final case class TenantApiServiceImpl( } } - override def updateTenant(id: String, tenantDelta: TenantDelta)(implicit - contexts: Seq[(String, String)], - toEntityMarshallerProblem: ToEntityMarshaller[Problem], - toEntityMarshallerTenant: ToEntityMarshaller[Tenant] - ): Route = authorize(ADMIN_ROLE) { - val operationLabel = s"Updating Tenant $id" - logger.info(operationLabel) - - val result: Future[Tenant] = for { - tenantUUID <- id.toFutureUUID - _ <- assertResourceAllowed(tenantUUID) - tenantManagement <- tenantManagementService.getTenantById(tenantUUID).map(_.toManagement) - tenantKind <- tenantManagement.kind.fold( - getTenantKindLoadingCertifiedAttributes(tenantManagement.attributes, tenantManagement.externalId) - )(Future.successful) - tenant <- tenantManagementService.updateTenant( - tenantUUID, - tenantDelta.fromAPI(tenantManagement.selfcareId, tenantManagement.features, tenantKind) - ) - } yield tenant.toApi - - onComplete(result) { - updateTenantResponse[Tenant](operationLabel)(updateTenant200) - } - } - override def internalUpsertTenant(seed: InternalTenantSeed)(implicit contexts: Seq[(String, String)], toEntityMarshallerProblem: ToEntityMarshaller[Problem], @@ -233,8 +207,8 @@ final case class TenantApiServiceImpl( override def selfcareUpsertTenant(seed: SelfcareTenantSeed)(implicit contexts: Seq[(String, String)], - toEntityMarshallerProblem: ToEntityMarshaller[Problem], - toEntityMarshallerTenant: ToEntityMarshaller[Tenant] + toEntityMarshallerTenant: ToEntityMarshaller[ResourceId], + toEntityMarshallerProblem: ToEntityMarshaller[Problem] ): Route = authorize(ADMIN_ROLE, API_ROLE, SECURITY_ROLE, INTERNAL_ROLE) { val operationLabel = s"Creating tenant with external id ${seed.externalId} via SelfCare request" logger.info(operationLabel) @@ -245,12 +219,7 @@ final case class TenantApiServiceImpl( def updateTenant(): Future[DependencyTenant] = tenantManagementService .updateTenant( tenant.id, - DependencyTenantDelta( - selfcareId = seed.selfcareId.some, - features = tenant.features, - mails = tenant.mails.map(_.toSeed), - kind = kind - ) + DependencyTenantDelta(selfcareId = seed.selfcareId.some, features = tenant.features, kind = kind) ) def verifyConflict(selfcareId: String): Future[DependencyTenant] = Future .failed(SelfcareIdConflict(tenant.id, selfcareId, seed.selfcareId)) @@ -260,17 +229,20 @@ final case class TenantApiServiceImpl( tenant.selfcareId.fold(updateTenant())(verifyConflict) } - val result: Future[Tenant] = for { + val result: Future[ResourceId] = for { existingTenant <- findTenant(seed.externalId) _ <- existingTenant.traverse(t => assertResourceAllowed(t.id)) tenant <- existingTenant .fold(createTenant(seed, Nil, now, getTenantKind(Nil, seed.externalId).fromAPI))(Future.successful) tenantKind <- getTenantKindLoadingCertifiedAttributes(tenant.attributes, tenant.externalId) - updatedTenant <- updateSelfcareId(tenant, tenantKind) - } yield updatedTenant.toApi + _ <- updateSelfcareId(tenant, tenantKind) + _ <- seed.digitalAddress.traverse(digitaAddress => + tenantManagementService.addTenantMail(tenant.id, digitaAddress.toDependency) + ) + } yield ResourceId(tenant.id) onComplete(result) { - selfcareUpsertTenantResponse[Tenant](operationLabel)(selfcareUpsertTenant200) + selfcareUpsertTenantResponse[ResourceId](operationLabel)(selfcareUpsertTenant200) } } @@ -555,12 +527,7 @@ final case class TenantApiServiceImpl( tenantManagementService .updateTenant( tenant.id, - DependencyTenantDelta( - selfcareId = tenant.selfcareId, - features = tenant.features, - mails = tenant.mails.map(_.toSeed), - kind = kind - ) + DependencyTenantDelta(selfcareId = tenant.selfcareId, features = tenant.features, kind = kind) ) for { @@ -713,7 +680,6 @@ final case class TenantApiServiceImpl( DependencyTenantDelta( selfcareId = updatedTenant.selfcareId, features = updatedTenant.features, - mails = updatedTenant.mails.map(_.toSeed), kind = tenantKind ) ) @@ -749,7 +715,6 @@ final case class TenantApiServiceImpl( DependencyTenantDelta( selfcareId = updatedTenant.selfcareId, features = updatedTenant.features, - mails = updatedTenant.mails.map(_.toSeed), kind = tenantKind ) ) @@ -886,4 +851,42 @@ final case class TenantApiServiceImpl( getTenantByExternalIdResponse[Tenant](operationLabel)(getTenantByExternalId200) } } + + override def addTenantMail(tenantId: String, mailSeed: MailSeed)(implicit + contexts: Seq[(String, String)], + toEntityMarshallerProblem: ToEntityMarshaller[Problem] + ): Route = authorize(ADMIN_ROLE, API_ROLE) { + val operationLabel = s"Adding mail of kind ${mailSeed.kind} to Tenant $tenantId" + logger.info(operationLabel) + + val result: Future[Unit] = for { + tenantUuid <- tenantId.toFutureUUID + requesterUuid <- getOrganizationIdFutureUUID(contexts) + _ <- assertRequesterAllowed(tenantUuid)(requesterUuid) + _ <- tenantManagementService.addTenantMail(tenantUuid, mailSeed.toDependency) + } yield () + + onComplete(result) { + addTenantMailResponse[Unit](operationLabel)(_ => addTenantMail204) + } + } + + override def deleteTenantMail(tenantId: String, mailId: String)(implicit + contexts: Seq[(String, String)], + toEntityMarshallerProblem: ToEntityMarshaller[Problem] + ): Route = authorize(ADMIN_ROLE, API_ROLE) { + val operationLabel = s"Deleting mail $mailId to Tenant $tenantId" + logger.info(operationLabel) + + val result: Future[Unit] = for { + tenantUuid <- tenantId.toFutureUUID + requesterUuid <- getOrganizationIdFutureUUID(contexts) + _ <- assertRequesterAllowed(tenantUuid)(requesterUuid) + _ <- tenantManagementService.deleteTenantMail(tenantUuid, mailId) + } yield () + + onComplete(result) { + deleteTenantMailResponse[Unit](operationLabel)(_ => deleteTenantMail204) + } + } } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/package.scala b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/package.scala index 117f54e..32d926f 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/package.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/api/impl/package.scala @@ -8,9 +8,8 @@ import spray.json.{DefaultJsonProtocol, RootJsonFormat} package object impl extends SprayJsonSupport with DefaultJsonProtocol { - implicit def mailSeedFormat: RootJsonFormat[MailSeed] = jsonFormat3(MailSeed) - implicit def mailFormat: RootJsonFormat[Mail] = jsonFormat4(Mail) - implicit def tenantDeltaFormat: RootJsonFormat[TenantDelta] = jsonFormat1(TenantDelta) + implicit def mailSeedFormat: RootJsonFormat[MailSeed] = jsonFormat3(MailSeed) + implicit def mailFormat: RootJsonFormat[Mail] = jsonFormat5(Mail) implicit def externalIdFormat: RootJsonFormat[ExternalId] = jsonFormat2(ExternalId) @@ -19,8 +18,7 @@ package object impl extends SprayJsonSupport with DefaultJsonProtocol { implicit def m2mAttributeSeedFormat: RootJsonFormat[M2MAttributeSeed] = jsonFormat1(M2MAttributeSeed) implicit def m2mTenantSeedFormat: RootJsonFormat[M2MTenantSeed] = jsonFormat3(M2MTenantSeed) - - implicit def selfcareTenantSeedFormat: RootJsonFormat[SelfcareTenantSeed] = jsonFormat3(SelfcareTenantSeed) + implicit def selfcareTenantSeedFormat: RootJsonFormat[SelfcareTenantSeed] = jsonFormat6(SelfcareTenantSeed) implicit def certifierFormat: RootJsonFormat[Certifier] = jsonFormat1(Certifier) implicit def tenantFeatureFormat: RootJsonFormat[TenantFeature] = jsonFormat1(TenantFeature) @@ -43,7 +41,8 @@ package object impl extends SprayJsonSupport with DefaultJsonProtocol { implicit def tenantVerifierFormat: RootJsonFormat[TenantVerifier] = jsonFormat4(TenantVerifier) implicit def tenantRevokerFormat: RootJsonFormat[TenantRevoker] = jsonFormat5(TenantRevoker) - implicit def tenantFormat: RootJsonFormat[Tenant] = jsonFormat10(Tenant) + implicit def resourceIdFormat: RootJsonFormat[ResourceId] = jsonFormat1(ResourceId) + implicit def tenantFormat: RootJsonFormat[Tenant] = jsonFormat12(Tenant) implicit def tenantsFormat: RootJsonFormat[Tenants] = jsonFormat2(Tenants) implicit def problemErrorFormat: RootJsonFormat[ProblemError] = jsonFormat2(ProblemError) implicit def problemFormat: RootJsonFormat[Problem] = jsonFormat6(Problem) diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/error/ResponseHandlers.scala b/src/main/scala/it/pagopa/interop/tenantprocess/error/ResponseHandlers.scala index f91bd7f..e2d3291 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/error/ResponseHandlers.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/error/ResponseHandlers.scala @@ -36,16 +36,6 @@ object ResponseHandlers extends AkkaResponses { case Failure(ex) => internalServerError(ex, logMessage) } - def updateTenantResponse[T](logMessage: String)( - success: T => Route - )(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route = - result match { - case Success(s) => success(s) - case Failure(ex: OperationForbidden.type) => forbidden(ex, logMessage) - case Failure(ex: TenantByIdNotFound) => notFound(ex, logMessage) - case Failure(ex) => internalServerError(ex, logMessage) - } - def internalUpsertTenantResponse[T](logMessage: String)( success: T => Route )(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route = @@ -203,4 +193,24 @@ object ResponseHandlers extends AkkaResponses { case Failure(ex: RegistryAttributeNotFound) => notFound(ex, logMessage) case Failure(ex) => internalServerError(ex, logMessage) } + + def addTenantMailResponse[T](logMessage: String)( + success: T => Route + )(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route = + result match { + case Success(s) => success(s) + case Failure(ex: OperationForbidden.type) => forbidden(ex, logMessage) + case Failure(ex: TenantByIdNotFound) => notFound(ex, logMessage) + case Failure(ex) => internalServerError(ex, logMessage) + } + + def deleteTenantMailResponse[T](logMessage: String)( + success: T => Route + )(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route = + result match { + case Success(s) => success(s) + case Failure(ex: OperationForbidden.type) => forbidden(ex, logMessage) + case Failure(ex: TenantByIdNotFound) => notFound(ex, logMessage) + case Failure(ex) => internalServerError(ex, logMessage) + } } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/service/TenantManagementService.scala b/src/main/scala/it/pagopa/interop/tenantprocess/service/TenantManagementService.scala index d296fb7..fed01fc 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/service/TenantManagementService.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/service/TenantManagementService.scala @@ -52,4 +52,8 @@ trait TenantManagementService { ec: ExecutionContext, readModel: ReadModelService ): Future[PaginatedResult[PersistentTenant]] + + def addTenantMail(tenantId: UUID, mailSeed: MailSeed)(implicit contexts: Seq[(String, String)]): Future[Unit] + + def deleteTenantMail(tenantId: UUID, mailId: String)(implicit contexts: Seq[(String, String)]): Future[Unit] } diff --git a/src/main/scala/it/pagopa/interop/tenantprocess/service/impl/TenantManagementServiceImpl.scala b/src/main/scala/it/pagopa/interop/tenantprocess/service/impl/TenantManagementServiceImpl.scala index 28a7800..33925d5 100644 --- a/src/main/scala/it/pagopa/interop/tenantprocess/service/impl/TenantManagementServiceImpl.scala +++ b/src/main/scala/it/pagopa/interop/tenantprocess/service/impl/TenantManagementServiceImpl.scala @@ -135,4 +135,28 @@ final case class TenantManagementServiceImpl( ec: ExecutionContext, readModel: ReadModelService ): Future[PaginatedResult[PersistentTenant]] = ReadModelTenantQueries.listConsumers(name, producerId, offset, limit) + + override def addTenantMail(tenantId: UUID, mailSeed: MailSeed)(implicit + contexts: Seq[(String, String)] + ): Future[Unit] = withHeaders { (bearerToken, correlationId) => + val request = tenantApi.addTenantMail(xCorrelationId = correlationId, tenantId = tenantId, mailSeed = mailSeed)( + BearerToken(bearerToken) + ) + invoker.invoke(request, s"Adding mail with id ${mailSeed.id} to tenant $tenantId").recoverWith { + case err: ApiError[_] if err.code == 404 => + Future.failed(TenantByIdNotFound(tenantId)) + } + } + + override def deleteTenantMail(tenantId: UUID, mailId: String)(implicit + contexts: Seq[(String, String)] + ): Future[Unit] = withHeaders { (bearerToken, correlationId) => + val request = tenantApi.deleteTenantMail(xCorrelationId = correlationId, tenantId = tenantId, mailId = mailId)( + BearerToken(bearerToken) + ) + invoker.invoke(request, s"Deleting mail ${mailId} to tenant $tenantId").recoverWith { + case err: ApiError[_] if err.code == 404 => + Future.failed(TenantByIdNotFound(tenantId)) + } + } } diff --git a/src/test/resources/authz.json b/src/test/resources/authz.json index edc0631..7bd98a7 100644 --- a/src/test/resources/authz.json +++ b/src/test/resources/authz.json @@ -147,6 +147,22 @@ "roles": [ "admin" ] + }, + { + "route": "addTenantMail", + "verb": "POST", + "roles": [ + "admin", + "api" + ] + }, + { + "route": "deleteTenantMail", + "verb": "DELETE", + "roles": [ + "admin", + "api" + ] } ] } \ No newline at end of file diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/authz/TenantApiServiceAuthzSpec.scala b/src/test/scala/it/pagopa/interop/tenantprocess/authz/TenantApiServiceAuthzSpec.scala index 0fe0b41..b6eabe6 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/authz/TenantApiServiceAuthzSpec.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/authz/TenantApiServiceAuthzSpec.scala @@ -188,11 +188,20 @@ class TenantApiServiceAuthzSpec extends ClusteredMUnitRouteTest with SpecData { ) } - test("Tenant api should accept authorized roles for updateTenant") { + test("Tenant api should accept authorized roles for addTenantMail") { validateAuthorization( - endpoints("updateTenant"), + endpoints("addTenantMail"), { implicit c: Seq[(String, String)] => - tenantService.updateTenant(c.find(_._1 == ORGANIZATION_ID_CLAIM).get.toString, fakeTenantDelta) + tenantService.addTenantMail(c.find(_._1 == ORGANIZATION_ID_CLAIM).get.toString, fakeMailSeed) + } + ) + } + + test("Tenant api should accept authorized roles for deleteTenantMail") { + validateAuthorization( + endpoints("deleteTenantMail"), + { implicit c: Seq[(String, String)] => + tenantService.deleteTenantMail(c.find(_._1 == ORGANIZATION_ID_CLAIM).get.toString, "fake") } ) } diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantCreationSpec.scala b/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantCreationSpec.scala index cbb1958..08c16f5 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantCreationSpec.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantCreationSpec.scala @@ -346,7 +346,7 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR mockGetAttributeById(updatedExistingAttributeId, updatedExistingAttribute) val expectedTenantUpdate = - TenantDelta(selfcareId = None, features = Nil, mails = Nil, kind = TenantKind.PA) + TenantDelta(selfcareId = None, features = Nil, kind = TenantKind.PA) mockUpdateTenant(existingTenant.id, expectedTenantUpdate) @@ -455,7 +455,7 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR mockGetAttributeById(updatedExistingAttributeId, updatedExistingAttribute) val expectedTenantUpdate = - TenantDelta(selfcareId = None, features = Nil, mails = Nil, kind = TenantKind.GSP) + TenantDelta(selfcareId = None, features = Nil, kind = TenantKind.GSP) mockUpdateTenant(existingTenant.id, expectedTenantUpdate) @@ -670,7 +670,7 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR mockUpdateTenantAttribute(tenantToModify.id, attributeId, dependencyAttribute) val expectedTenantUpdate = - TenantDelta(selfcareId = None, features = Nil, mails = Nil, kind = TenantKind.PA) + TenantDelta(selfcareId = None, features = Nil, kind = TenantKind.PA) mockComputeAgreementState(attributeId, CompactTenant(tenantId, Nil)) @@ -856,7 +856,7 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR mockGetAttributeById(updatedExistingAttributeId, updatedExistingAttribute) val expectedTenantUpdate = - TenantDelta(selfcareId = None, features = Nil, mails = Nil, kind = TenantKind.PA) + TenantDelta(selfcareId = None, features = Nil, kind = TenantKind.PA) mockUpdateTenant(existingTenant.id, expectedTenantUpdate) @@ -898,10 +898,12 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR features = Nil, attributes = Nil, name = "test_name", - kind = TenantKind.PA + kind = TenantKind.PA, + onboardedAt = Some(timestamp), + subUnitType = Some(TenantUnitType.AOO) ) val expectedTenantUpdate = - TenantDelta(selfcareId = Some(seed.selfcareId), features = Nil, mails = Nil, kind = TenantKind.PA) + TenantDelta(selfcareId = Some(seed.selfcareId), features = Nil, kind = TenantKind.PA) mockDateTimeGet() mockUuidGet(tenantId) @@ -929,10 +931,12 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR features = Nil, attributes = Nil, name = "test_name", - kind = TenantKind.PRIVATE + kind = TenantKind.PRIVATE, + onboardedAt = Some(timestamp), + subUnitType = Some(TenantUnitType.AOO) ) val expectedTenantUpdate = - TenantDelta(selfcareId = Some(seed.selfcareId), features = Nil, mails = Nil, kind = TenantKind.PRIVATE) + TenantDelta(selfcareId = Some(seed.selfcareId), features = Nil, kind = TenantKind.PRIVATE) mockDateTimeGet() mockUuidGet(tenantId) @@ -947,7 +951,7 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR } } - "SelfCare request - Update of an existing tenant must succeed if SelfCare ID is not set" in { + "SelfCare request - Update of an existing tenant must succeed if SelfCare ID is not set without mail seed" in { implicit val context: Seq[(String, String)] = selfcareContext val tenantId = organizationId @@ -962,7 +966,6 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR TenantDelta( selfcareId = Some(seed.selfcareId), features = Seq(TenantFeature(certifier = Some(Certifier("something")))), - mails = Nil, kind = TenantKind.PA ) @@ -976,6 +979,36 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR } } + "SelfCare request - Update of an existing tenant must succeed if SelfCare ID is not set but with digitalAddress" in { + implicit val context: Seq[(String, String)] = selfcareContext + + val tenantId = organizationId + val seed = selfcareTenantSeed.copy(digitalAddress = Some(mailSeed)) + val tenant = persistentTenant.copy( + id = tenantId, + selfcareId = None, + features = List(PersistentTenantFeature.PersistentCertifier("something")) + ) + + val expectedTenantUpdate = + TenantDelta( + selfcareId = Some(seed.selfcareId), + features = Seq(TenantFeature(certifier = Some(Certifier("something")))), + kind = TenantKind.PA + ) + + mockDateTimeGet() + + mockGetTenantByExternalId(PersistentExternalId(seed.externalId.origin, seed.externalId.value), tenant) + mockUpdateTenant(tenantId, expectedTenantUpdate) + + mockAddTenantMail(tenantId, dependencyMailSeed) + + Get() ~> tenantService.selfcareUpsertTenant(seed) ~> check { + assert(status == StatusCodes.OK) + } + } + "SelfCare request - Update should not be performed if existing SelfCare ID is equal to the request" in { implicit val context: Seq[(String, String)] = selfcareContext @@ -1056,7 +1089,6 @@ class TenantCreationSpec extends AnyWordSpecLike with SpecHelper with ScalatestR TenantDelta( selfcareId = Some(seed.selfcareId), features = Seq(TenantFeature(certifier = Some(Certifier("something")))), - mails = Nil, kind = TenantKind.PA ) diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantUpdateSpec.scala b/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantUpdateSpec.scala index 545f271..a0d5e20 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantUpdateSpec.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/provider/TenantUpdateSpec.scala @@ -1,88 +1,60 @@ package it.pagopa.interop.tenantprocess.provider -import cats.syntax.all._ import akka.http.scaladsl.model.StatusCodes import it.pagopa.interop.tenantprocess.api.impl.TenantApiMarshallerImpl._ import akka.http.scaladsl.testkit.ScalatestRouteTest -import it.pagopa.interop.commons.utils.ORGANIZATION_ID_CLAIM import it.pagopa.interop.tenantprocess.utils.SpecHelper import org.scalatest.wordspec.AnyWordSpecLike -import it.pagopa.interop.tenantprocess.api.adapters.ApiAdapters._ -import it.pagopa.interop.tenantprocess.api.adapters.TenantManagementAdapters._ -import it.pagopa.interop.tenantprocess.api.adapters.ReadModelTenantAdapters._ +import it.pagopa.interop.commons.utils.Digester.toSha256 -import java.util.UUID -import it.pagopa.interop.tenantprocess.model.TenantDelta -import it.pagopa.interop.tenantprocess.model.Tenant +import it.pagopa.interop.tenantprocess.model._ import it.pagopa.interop.tenantmanagement.client.{model => Dependency} -import it.pagopa.interop.tenantprocess.model.MailSeed -import it.pagopa.interop.tenantprocess.model.MailKind - -import java.time.OffsetDateTime +import java.util.UUID class TenantUpdateSpec extends AnyWordSpecLike with SpecHelper with ScalatestRouteTest { - "Tenant updated should not alter the tenant management behaviour when no mails" in { + "Add tenant mail" in { implicit val contexts: Seq[(String, String)] = adminContext - val tenantId: UUID = organizationId - val tenantDelta: TenantDelta = TenantDelta(mails = Nil) + val mailSeed: MailSeed = MailSeed(MailKind.CONTACT_EMAIL, "foo@bar.it", None) + val dependencyMailSeed: Dependency.MailSeed = + Dependency.MailSeed(toSha256("foo@bar.it".getBytes()), Dependency.MailKind.CONTACT_EMAIL, "foo@bar.it", None) + + mockAddTenantMail(organizationId, dependencyMailSeed) + + Post() ~> tenantService.addTenantMail(organizationId.toString, mailSeed) ~> check { + assert(status == StatusCodes.NoContent) + } + } + + "Delete tenant mail" in { + implicit val contexts: Seq[(String, String)] = adminContext - val dependencyTenant: Dependency.Tenant = persistentTenant.toManagement - val expected: Tenant = dependencyTenant.toApi + val mailId: String = toSha256("foo@bar.it".getBytes()) - mockGetTenantById(tenantId, persistentTenant) - mockUpdateTenant( - tenantId, - tenantDelta.fromAPI(dependencyTenant.selfcareId, dependencyTenant.features, kind = Dependency.TenantKind.PA), - dependencyTenant - ) + mockDeleteTenantMail(organizationId, mailId) - Post() ~> tenantService.updateTenant(tenantId.toString, tenantDelta) ~> check { - assert(status == StatusCodes.OK) - assert(entityAs[Tenant] == expected) + Post() ~> tenantService.deleteTenantMail(organizationId.toString, mailId) ~> check { + assert(status == StatusCodes.NoContent) } } - "Tenant updated should not alter the tenant management behaviour when there are mails" in { + "Add tenant mail fail if tenant is not the requester" in { implicit val contexts: Seq[(String, String)] = adminContext - val tenantId: UUID = organizationId - val tenantDelta: TenantDelta = TenantDelta(mails = - MailSeed(kind = MailKind.CONTACT_EMAIL, address = "foo@bar.com", description = "awe".some) :: Nil - ) - - val dependencyTenant: Dependency.Tenant = persistentTenant.toManagement.copy(mails = - Dependency.Mail( - kind = Dependency.MailKind.CONTACT_EMAIL, - address = "foo@bar.com", - createdAt = OffsetDateTime.now(), - description = "awe".some - ) :: Nil - ) - val expected: Tenant = dependencyTenant.toApi - - mockGetTenantById(tenantId, persistentTenant) - mockUpdateTenant( - tenantId, - tenantDelta.fromAPI(dependencyTenant.selfcareId, dependencyTenant.features, kind = Dependency.TenantKind.PA), - dependencyTenant - ) - - Post() ~> tenantService.updateTenant(tenantId.toString, tenantDelta) ~> check { - assert(status == StatusCodes.OK) - assert(entityAs[Tenant] == expected) + val mailSeed: MailSeed = MailSeed(MailKind.CONTACT_EMAIL, "foo@bar.it", None) + + Post() ~> tenantService.addTenantMail(UUID.randomUUID().toString(), mailSeed) ~> check { + assert(status == StatusCodes.Forbidden) } } - "Tenant updated should not be allowed be user not belonging to the Tenant" in { - implicit val contexts: Seq[(String, String)] = - adminContext.filter(_._1 != ORGANIZATION_ID_CLAIM) :+ ORGANIZATION_ID_CLAIM -> UUID.randomUUID().toString + "Delete tenant mail fail if tenant is not the requester" in { + implicit val contexts: Seq[(String, String)] = adminContext - val tenantId: UUID = UUID.randomUUID() - val tenantDelta: TenantDelta = TenantDelta(mails = Nil) + val mailId: String = toSha256("foo@bar.it".getBytes()) - Post() ~> tenantService.updateTenant(tenantId.toString, tenantDelta) ~> check { + Post() ~> tenantService.deleteTenantMail(UUID.randomUUID().toString(), mailId) ~> check { assert(status == StatusCodes.Forbidden) } } diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/utils/FakeDependencies.scala b/src/test/scala/it/pagopa/interop/tenantprocess/utils/FakeDependencies.scala index cf9e869..eab0982 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/utils/FakeDependencies.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/utils/FakeDependencies.scala @@ -9,7 +9,8 @@ import it.pagopa.interop.tenantmanagement.model.tenant.{ PersistentTenant, PersistentTenantAttribute, PersistentTenantFeature, - PersistentTenantKind + PersistentTenantKind, + PersistentTenantUnitType } import it.pagopa.interop.attributeregistrymanagement.model.persistence.attribute.{Certified, PersistentAttribute} import it.pagopa.interop.catalogmanagement.model.CatalogItem @@ -73,6 +74,13 @@ object FakeDependencies extends SpecData { contexts: Seq[(String, String)] ): Future[Tenant] = Future.successful(fakeTenant) + override def addTenantMail(tenantId: UUID, seed: MailSeed)(implicit contexts: Seq[(String, String)]): Future[Unit] = + Future.successful(()) + + override def deleteTenantMail(tenantId: UUID, mailId: String)(implicit + contexts: Seq[(String, String)] + ): Future[Unit] = Future.successful(()) + override def addTenantAttribute(tenantId: UUID, seed: TenantAttribute)(implicit contexts: Seq[(String, String)] ): Future[Tenant] = Future.successful(fakeTenant) @@ -189,7 +197,9 @@ object FakeDependencies extends SpecData { updatedAt = None, mails = Nil, name = "test_name", - kind = Some(PersistentTenantKind.PA) + kind = Some(PersistentTenantKind.PA), + onboardedAt = None, + subUnitType = Some(PersistentTenantUnitType.Aoo) ) val fakeAttribute: PersistentCertifiedAttribute = diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecData.scala b/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecData.scala index a83496f..5fbd099 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecData.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecData.scala @@ -11,7 +11,8 @@ import it.pagopa.interop.tenantmanagement.model.tenant.{ PersistentTenantAttribute, PersistentTenantRevoker, PersistentTenantVerifier, - PersistentVerifiedAttribute + PersistentVerifiedAttribute, + PersistentTenantUnitType } import it.pagopa.interop.tenantprocess.model._ import it.pagopa.interop.agreementmanagement.model.agreement.{ @@ -28,20 +29,26 @@ import it.pagopa.interop.catalogmanagement.model.{ CatalogDescriptor, CatalogItem, Published, - Rest + Rest, + Deliver } - +import it.pagopa.interop.commons.utils.Digester.toSha256 +import it.pagopa.interop.commons.utils.service.OffsetDateTimeSupplier import java.time.{OffsetDateTime, ZoneOffset} import java.util.UUID -import it.pagopa.interop.commons.utils.service.OffsetDateTimeSupplier -import it.pagopa.interop.catalogmanagement.model.Deliver trait SpecData { final val timestamp = OffsetDateTime.of(2022, 12, 31, 11, 22, 33, 44, ZoneOffset.UTC) val tenantId = UUID.randomUUID() val internalAttributeSeed: InternalAttributeSeed = InternalAttributeSeed("IPA", s"int-attribute-${UUID.randomUUID()}") val m2mAttributeSeed: M2MAttributeSeed = M2MAttributeSeed(s"m2m-attribute-${UUID.randomUUID()}") - + val mailSeed: MailSeed = MailSeed(MailKind.DIGITAL_ADDRESS, address = "foo@bar.it", None) + val dependencyMailSeed: Dependency.MailSeed = Dependency.MailSeed( + toSha256("foo@bar.it".getBytes()), + Dependency.MailKind.DIGITAL_ADDRESS, + address = "foo@bar.it", + None + ) val internalTenantSeed: InternalTenantSeed = InternalTenantSeed(ExternalId("IPA", s"tenant-${UUID.randomUUID()}"), Seq(internalAttributeSeed), "test_name") val internalTenantSeedNotIpa: InternalTenantSeed = @@ -51,9 +58,23 @@ trait SpecData { val m2mTenantSeedNotIpa: M2MTenantSeed = M2MTenantSeed(ExternalId("NOT_IPA", s"tenant-${UUID.randomUUID()}"), Seq(m2mAttributeSeed), "test_name") val selfcareTenantSeed: SelfcareTenantSeed = - SelfcareTenantSeed(ExternalId("IPA", s"tenant-${UUID.randomUUID()}"), UUID.randomUUID().toString, "test_name") + SelfcareTenantSeed( + ExternalId("IPA", s"tenant-${UUID.randomUUID()}"), + UUID.randomUUID().toString, + "test_name", + None, + timestamp, + TenantUnitType.AOO + ) val selfcareTenantSeedNotIpa: SelfcareTenantSeed = - SelfcareTenantSeed(ExternalId("NOT_IPA", s"tenant-${UUID.randomUUID()}"), UUID.randomUUID().toString, "test_name") + SelfcareTenantSeed( + ExternalId("NOT_IPA", s"tenant-${UUID.randomUUID()}"), + UUID.randomUUID().toString, + "test_name", + None, + timestamp, + TenantUnitType.AOO + ) val dependencyTenant: Dependency.Tenant = Dependency.Tenant( id = tenantId, @@ -65,7 +86,9 @@ trait SpecData { updatedAt = None, mails = Nil, name = "test_name", - kind = None + kind = None, + onboardedAt = Some(timestamp), + subUnitType = Some(Dependency.TenantUnitType.AOO) ) val persistentAttribute: PersistentAttribute = PersistentAttribute( @@ -105,7 +128,9 @@ trait SpecData { updatedAt = None, mails = Nil, name = "test_name", - kind = None + kind = None, + onboardedAt = Some(timestamp), + subUnitType = Some(PersistentTenantUnitType.Aoo) ) val persistentTenantNotIPA: PersistentTenant = PersistentTenant( @@ -118,10 +143,12 @@ trait SpecData { updatedAt = None, mails = Nil, name = "test_name", - kind = None + kind = None, + onboardedAt = Some(timestamp), + subUnitType = Some(PersistentTenantUnitType.Aoo) ) - val fakeTenantDelta: TenantDelta = TenantDelta(mails = Nil) + val fakeMailSeed = MailSeed(MailKind.CONTACT_EMAIL, address = "fakeAddress", description = None) val persistentTenantVerifier: PersistentTenantVerifier = PersistentTenantVerifier( id = UUID.randomUUID(), diff --git a/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecHelper.scala b/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecHelper.scala index 45af901..c036c32 100644 --- a/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecHelper.scala +++ b/src/test/scala/it/pagopa/interop/tenantprocess/utils/SpecHelper.scala @@ -148,6 +148,20 @@ trait SpecHelper extends MockFactory with SpecData { .once() .returns(Future.successful(result)) + def mockAddTenantMail(tenantId: UUID, payload: MailSeed)(implicit contexts: Seq[(String, String)]) = + (mockTenantManagement + .addTenantMail(_: UUID, _: MailSeed)(_: Seq[(String, String)])) + .expects(tenantId, payload, contexts) + .once() + .returns(Future.successful(())) + + def mockDeleteTenantMail(tenantId: UUID, mailId: String)(implicit contexts: Seq[(String, String)]) = + (mockTenantManagement + .deleteTenantMail(_: UUID, _: String)(_: Seq[(String, String)])) + .expects(tenantId, mailId, contexts) + .once() + .returns(Future.successful(())) + def mockAddTenantAttribute(tenantId: UUID, attribute: TenantAttribute, result: Tenant = dependencyTenant)(implicit contexts: Seq[(String, String)] ) =