Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIN-4332 - Update of daily calls with the same value of the previous version is not allowed #196

Merged
merged 3 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -230,6 +230,7 @@ final case class PurposeApiServiceImpl(
eService => if (eService.mode == Deliver) Future.unit else Future.failed(EServiceNotInDeliverMode(eService.id)),
seed.isFreeOfCharge,
seed.freeOfChargeReason,
seed.dailyCalls,
(_, tenantKind) =>
seed
.toManagement(schemaOnlyValidation = true)(tenantKind)
Expand All @@ -252,6 +253,7 @@ final case class PurposeApiServiceImpl(
eService => if (eService.mode == Receive) Future.unit else Future.failed(EServiceNotInReceiveMode(eService.id)),
seed.isFreeOfCharge,
seed.freeOfChargeReason,
seed.dailyCalls,
(purpose, tenantKind) =>
seed
.toManagement(schemaOnlyValidation = true, purpose.riskAnalysisForm.map(_.toApi))(tenantKind)
Expand All @@ -266,13 +268,15 @@ final case class PurposeApiServiceImpl(
eServiceModeCheck: CatalogItem => Future[Unit],
isFreeOfCharge: Boolean,
freeOfChargeReason: Option[String],
dailyCalls: Int,
payload: (PersistentPurpose, PersistentTenantKind) => Future[PurposeManagementDependency.PurposeUpdateContent]
)(implicit contexts: Seq[(String, String)]): Future[Purpose] = for {
requesterOrgId <- getOrganizationIdFutureUUID(contexts)
purposeUUID <- purposeId.toFutureUUID
purpose <- purposeManagementService.getPurposeById(purposeUUID)
_ <- assertOrganizationIsAConsumer(requesterOrgId, purpose.consumerId)
_ <- assertPurposeIsInDraftState(purpose)
_ <- assertDailyCallsIsDifferentThanBefore(purpose, dailyCalls)
eService <- catalogManagementService.getEServiceById(purpose.eserviceId)
_ <- eServiceModeCheck(eService)
_ <- checkFreeOfCharge(isFreeOfCharge, freeOfChargeReason)
Expand Down Expand Up @@ -615,21 +619,6 @@ final case class PurposeApiServiceImpl(
dailyCalls = dailyCalls
)

def getDailyCalls(versions: Seq[PersistentPurposeVersion]): Int = {

val ordering: Ordering[OffsetDateTime] = Ordering(Ordering.by[OffsetDateTime, Long](_.toEpochSecond).reverse)

val latestNoWaiting: Option[Int] = versions
.filterNot(_.state == WaitingForApproval)
.sortBy(_.createdAt)(ordering)
.map(_.dailyCalls)
.headOption

val latestAll: Option[Int] = versions.sortBy(_.createdAt)(ordering).map(_.dailyCalls).headOption

latestNoWaiting.getOrElse(latestAll.getOrElse(0))
}

val result: Future[Purpose] = for {
organizationId <- getOrganizationIdFutureUUID(contexts)
tenant <- tenantManagementService.getTenantById(organizationId)
Expand All @@ -648,6 +637,21 @@ final case class PurposeApiServiceImpl(
onComplete(result) { clonePurposeResponse[Purpose](operationLabel)(clonePurpose200) }
}

private def getDailyCalls(versions: Seq[PersistentPurposeVersion]): Int = {

val ordering: Ordering[OffsetDateTime] = Ordering(Ordering.by[OffsetDateTime, Long](_.toEpochSecond).reverse)

val latestNoWaiting: Option[Int] = versions
.filterNot(_.state == WaitingForApproval)
.sortBy(_.createdAt)(ordering)
.map(_.dailyCalls)
.headOption

val latestAll: Option[Int] = versions.sortBy(_.createdAt)(ordering).map(_.dailyCalls).headOption

latestNoWaiting.getOrElse(latestAll.getOrElse(0))
}

override def retrieveLatestRiskAnalysisConfiguration(tenantKind: Option[String])(implicit
contexts: Seq[(String, String)],
toEntityMarshallerRiskAnalysisFormConfigResponse: ToEntityMarshaller[RiskAnalysisFormConfigResponse],
Expand Down Expand Up @@ -734,6 +738,13 @@ final case class PurposeApiServiceImpl(
else Future.failed(PurposeNotInDraftState(purpose.id))
}

private def assertDailyCallsIsDifferentThanBefore(purpose: PersistentPurpose, dailyCalls: Int): Future[Unit] = {
val previousDailyCalls = getDailyCalls(purpose.versions)
if (previousDailyCalls != dailyCalls)
Future.successful(())
else Future.failed(DailyCallsEqualThanBefore(purpose.id))
}

private def isRiskAnalysisFormValid(
riskAnalysisForm: Option[RiskAnalysisForm],
schemaOnlyValidation: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ object ResponseHandlers extends AkkaResponses {
case Failure(ex: EServiceNotInDeliverMode) => badRequest(ex, logMessage)
case Failure(ex: TenantNotFound) => badRequest(ex, logMessage)
case Failure(ex: AgreementNotFound) => badRequest(ex, logMessage)
case Failure(ex: DailyCallsEqualThanBefore) => badRequest(ex, logMessage)
case Failure(ex: OrganizationIsNotTheConsumer) => forbidden(ex, logMessage)
case Failure(ex: PurposeNotInDraftState) => forbidden(ex, logMessage)
case Failure(ex: PurposeNotFound) => notFound(ex, logMessage)
Expand All @@ -110,6 +111,7 @@ object ResponseHandlers extends AkkaResponses {
case Failure(ex: EServiceNotInReceiveMode) => badRequest(ex, logMessage)
case Failure(ex: TenantNotFound) => badRequest(ex, logMessage)
case Failure(ex: AgreementNotFound) => badRequest(ex, logMessage)
case Failure(ex: DailyCallsEqualThanBefore) => badRequest(ex, logMessage)
case Failure(ex: OrganizationIsNotTheConsumer) => forbidden(ex, logMessage)
case Failure(ex: PurposeNotInDraftState) => forbidden(ex, logMessage)
case Failure(ex: PurposeNotFound) => notFound(ex, logMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,6 @@ object PurposeProcessErrors {
extends ComponentError("0026", s"EService ${eServiceId.toString} has not Receive mode")
final case class RiskAnalysisNotFound(eServiceId: UUID, riskAnalysisId: UUID)
extends ComponentError("0027", s"EService $eServiceId does not contain Risk Analysis $riskAnalysisId")

final case class DailyCallsEqualThanBefore(purposeId: UUID)
extends ComponentError("0028", s"Purpose $purposeId has the same dailyCalls")
nttdata-rtorsoli marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,35 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
status shouldEqual StatusCodes.OK
}
}
"fail if daily calls attribute has the same value of previous version" in {

val purposeId = UUID.randomUUID()
val eserviceId = UUID.randomUUID()
val consumerId = UUID.randomUUID()
val purposeUpdateContent =
PurposeUpdateContent(
title = "A title",
description = "A description",
isFreeOfCharge = false,
riskAnalysisForm = None,
dailyCalls = 1000
)

val purpose =
SpecData.purpose.copy(eserviceId = eserviceId, consumerId = consumerId, versions = Seq(SpecData.purposeVersion))

implicit val context: Seq[(String, String)] =
Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> consumerId.toString)

mockPurposeRetrieve(purposeId, purpose)

Post() ~> service.updatePurpose(purposeId.toString, purposeUpdateContent) ~> check {
status shouldEqual StatusCodes.BadRequest
val problem = responseAs[Problem]
problem.status shouldBe StatusCodes.BadRequest.intValue
problem.errors.head.code shouldBe "012-0028"
}
}
"fail if case of eService with Receive mode" in {

val purposeId = UUID.randomUUID()
Expand Down Expand Up @@ -1601,6 +1630,35 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
status shouldEqual StatusCodes.OK
}
}
"fail if daily calls attribute has the same value of previous version" in {

val purposeId = UUID.randomUUID()
val eserviceId = UUID.randomUUID()
val consumerId = UUID.randomUUID()

val reversePurposeUpdateContent =
ReversePurposeUpdateContent(
title = "A title",
description = "A description",
isFreeOfCharge = false,
dailyCalls = 1000
)

val purpose =
SpecData.purpose.copy(eserviceId = eserviceId, consumerId = consumerId, versions = Seq(SpecData.purposeVersion))

implicit val context: Seq[(String, String)] =
Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> consumerId.toString)

mockPurposeRetrieve(purposeId, purpose)

Post() ~> service.updateReversePurpose(purposeId.toString, reversePurposeUpdateContent) ~> check {
status shouldEqual StatusCodes.BadRequest
val problem = responseAs[Problem]
problem.status shouldBe StatusCodes.BadRequest.intValue
problem.errors.head.code shouldBe "012-0028"
}
}
"fail if case of eService with Deliver mode" in {

val purposeId = UUID.randomUUID()
Expand Down
Loading