Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinovega committed Sep 11, 2024
1 parent 11f592b commit 2ec4585
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 37 deletions.
38 changes: 11 additions & 27 deletions daikoku/app/controllers/ApiController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2141,33 +2141,17 @@ class ApiController(
AuditTrailEvent(s"@{user.name} has ask to transfer subscription @{subscriptionId} to team @{teamId}"))(teamId, ctx) { team => {

(for {
transferToken <- EitherT.pure[Future, AppError](decrypt(env.config.cypherSecret, (ctx.request.body \ "token").as[String], ctx.tenant))
transfer <- EitherT.fromOptionF[Future, AppError, ApiSubscriptionTransfer](env.dataStore.apiSubscriptionTransferRepo.forTenant(ctx.tenant).findOneNotDeleted(Json.obj("token" -> transferToken)),
AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](transfer.subscription.value == subscriptionId, (), AppError.EntityConflict("Subscription"))
subscription <- EitherT.fromOptionF[Future, AppError, ApiSubscription](env.dataStore.apiSubscriptionRepo.forTenant(ctx.tenant).findByIdNotDeleted(transfer.subscription), AppError.SubscriptionNotFound)
_ <- EitherT.cond[Future][AppError, Unit](subscription.parent.isEmpty, (), AppError.EntityConflict("Subscription is part of aggregation"))
api <- EitherT.fromOptionF[Future, AppError, Api](env.dataStore.apiRepo.forTenant(ctx.tenant).findByIdNotDeleted(subscription.api), AppError.ApiNotFound)
plan <- EitherT.fromOptionF[Future, AppError, UsagePlan](env.dataStore.usagePlanRepo.forTenant(ctx.tenant).findByIdNotDeleted(subscription.plan), AppError.PlanNotFound)
_ <- EitherT.cond[Future][AppError, Unit](api.visibility == ApiVisibility.Public || api.authorizedTeams.contains(team.id), (), AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](plan.visibility == UsagePlanVisibility.Public || plan.authorizedTeams.contains(team.id), (), AppError.Unauthorized)
childSubscriptions <- EitherT.liftF[Future, AppError, Seq[ApiSubscription]](env.dataStore.apiSubscriptionRepo.forTenant(ctx.tenant).findNotDeleted(Json.obj("parent" -> subscription.id.asJson)))
childApis <- EitherT.liftF[Future, AppError, Seq[Api]](env.dataStore.apiRepo.forTenant(ctx.tenant).findNotDeleted(Json.obj("_id" -> Json.obj("$in" -> JsArray(childSubscriptions.map(_.api.asJson))))))
childPlans <- EitherT.liftF[Future, AppError, Seq[UsagePlan]](env.dataStore.usagePlanRepo.forTenant(ctx.tenant).findNotDeleted(Json.obj("_id" -> Json.obj("$in" -> JsArray(childSubscriptions.map(_.plan.asJson))))))
_ <- EitherT.cond[Future][AppError, Unit](childApis.forall(a => a.visibility == ApiVisibility.Public || a.authorizedTeams.contains(team.id)), (), AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](childPlans.forall(p => p.visibility == UsagePlanVisibility.Public || p.authorizedTeams.contains(team.id)), (), AppError.Unauthorized)
teamSubscriptions <- EitherT.liftF[Future, AppError, Seq[ApiSubscription]](env.dataStore.apiSubscriptionRepo.forTenant(ctx.tenant).findNotDeleted(Json.obj("team" -> team.id.asJson)))
_ <- EitherT.cond[Future][AppError, Unit]((childPlans :+ plan).forall(p => p.allowMultipleKeys.getOrElse(false) || !teamSubscriptions.exists(s => s.plan == p.id)), (), AppError.EntityConflict("plan not allow multiple subscription"))
_ <- apiService.transferSubscription(team, subscription, childSubscriptions, ctx.tenant, ctx.user)
otoroshiSettings <- EitherT.fromOption[Future][AppError, OtoroshiSettings](plan.otoroshiTarget.flatMap(target => ctx.tenant.otoroshiSettings.find(_.id == target.otoroshiSettings)), AppError.EntityNotFound("Otoroshi settings"))
apk <- EitherT[Future, AppError, ActualOtoroshiApiKey](otoroshiClient.getApikey(subscription.apiKey.clientId)(otoroshiSettings))
newApk = apk.copy(clientName = s"daikoku-api-key-${api.humanReadableId}-${plan.customName
.getOrElse(plan.typeName)
.urlPathSegmentSanitized}-${team.humanReadableId}-${System
.currentTimeMillis()}-${api.currentVersion.value}",
metadata = apk.metadata + ("daikoku_transfer_to_team_id" -> team.id.value) + ("daikoku_transfer_to_team" -> team.name))
_ <- EitherT[Future, AppError, ActualOtoroshiApiKey](otoroshiClient.updateApiKey(newApk)(otoroshiSettings))

extract <- apiService.checkAndExtractTransferLink(ctx.tenant, subscriptionId, (ctx.request.body \ "token").as[String], team)
otoroshiSettings <- EitherT.fromOption[Future][AppError, OtoroshiSettings](extract.plan.otoroshiTarget.flatMap(target => ctx.tenant.otoroshiSettings.find(_.id == target.otoroshiSettings)), AppError.EntityNotFound("Otoroshi settings"))
_ <- apiService.transferSubscription(
newTeam = team,
subscription = extract.subscription,
childs = extract.childSubscriptions,
tenant = ctx.tenant,
user = ctx.user,
api = extract.api,
plan = extract.plan,
otoroshiSettings = otoroshiSettings)
} yield Ok(Json.obj("done" -> true)))
.leftMap(_.render())
.merge
Expand Down
38 changes: 35 additions & 3 deletions daikoku/app/utils/ApiService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2607,10 +2607,35 @@ class ApiService(
} yield Ok(Json.obj("creation" -> "refused"))
}

def transferSubscription(newTeam: Team, subscription: ApiSubscription, childs: Seq[ApiSubscription], tenant: Tenant, user: User) =
case class ExtractTransferLink(
subscription: ApiSubscription,
childSubscriptions: Seq[ApiSubscription],
plan: UsagePlan,
api: Api)

def checkAndExtractTransferLink(tenant: Tenant, subscriptionId: String, token: String, team: Team): EitherT[Future, AppError, ExtractTransferLink] =
for {
transferToken <- EitherT.pure[Future, AppError](decrypt(env.config.cypherSecret, token, tenant))
transfer <- EitherT.fromOptionF[Future, AppError, ApiSubscriptionTransfer](env.dataStore.apiSubscriptionTransferRepo.forTenant(tenant).findOneNotDeleted(Json.obj("token" -> transferToken)),
AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](transfer.subscription.value == subscriptionId, (), AppError.EntityConflict("Subscription"))
subscription <- EitherT.fromOptionF[Future, AppError, ApiSubscription](env.dataStore.apiSubscriptionRepo.forTenant(tenant).findByIdNotDeleted(transfer.subscription), AppError.SubscriptionNotFound)
_ <- EitherT.cond[Future][AppError, Unit](subscription.parent.isEmpty, (), AppError.EntityConflict("Subscription is part of aggregation"))
api <- EitherT.fromOptionF[Future, AppError, Api](env.dataStore.apiRepo.forTenant(tenant).findByIdNotDeleted(subscription.api), AppError.ApiNotFound)
plan <- EitherT.fromOptionF[Future, AppError, UsagePlan](env.dataStore.usagePlanRepo.forTenant(tenant).findByIdNotDeleted(subscription.plan), AppError.PlanNotFound)
_ <- EitherT.cond[Future][AppError, Unit](api.visibility == ApiVisibility.Public || api.authorizedTeams.contains(team.id), (), AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](plan.visibility == UsagePlanVisibility.Public || plan.authorizedTeams.contains(team.id), (), AppError.Unauthorized)
childSubscriptions <- EitherT.liftF[Future, AppError, Seq[ApiSubscription]](env.dataStore.apiSubscriptionRepo.forTenant(tenant).findNotDeleted(Json.obj("parent" -> subscription.id.asJson)))
childApis <- EitherT.liftF[Future, AppError, Seq[Api]](env.dataStore.apiRepo.forTenant(tenant).findNotDeleted(Json.obj("_id" -> Json.obj("$in" -> JsArray(childSubscriptions.map(_.api.asJson))))))
childPlans <- EitherT.liftF[Future, AppError, Seq[UsagePlan]](env.dataStore.usagePlanRepo.forTenant(tenant).findNotDeleted(Json.obj("_id" -> Json.obj("$in" -> JsArray(childSubscriptions.map(_.plan.asJson))))))
_ <- EitherT.cond[Future][AppError, Unit](childApis.forall(a => a.visibility == ApiVisibility.Public || a.authorizedTeams.contains(team.id)), (), AppError.Unauthorized)
_ <- EitherT.cond[Future][AppError, Unit](childPlans.forall(p => p.visibility == UsagePlanVisibility.Public || p.authorizedTeams.contains(team.id)), (), AppError.Unauthorized)
teamSubscriptions <- EitherT.liftF[Future, AppError, Seq[ApiSubscription]](env.dataStore.apiSubscriptionRepo.forTenant(tenant).findNotDeleted(Json.obj("team" -> team.id.asJson)))
_ <- EitherT.cond[Future][AppError, Unit]((childPlans :+ plan).forall(p => p.allowMultipleKeys.getOrElse(false) || !teamSubscriptions.exists(s => s.plan == p.id)), (), AppError.EntityConflict("plan not allow multiple subscription"))
} yield ExtractTransferLink(subscription, childSubscriptions, plan, api)

def transferSubscription(newTeam: Team, subscription: ApiSubscription, childs: Seq[ApiSubscription], tenant: Tenant, user: User, plan: UsagePlan, api: Api, otoroshiSettings: OtoroshiSettings) =
for {
//todo: update apkname ?
//todo: update apk metadata to set new team name ?
result <- EitherT.liftF[Future, AppError, Long](env.dataStore.apiSubscriptionRepo.forTenant(tenant).updateManyByQuery(
Json.obj(
"_id" -> Json
Expand All @@ -2620,6 +2645,13 @@ class ApiService(
"$set" -> Json.obj("team" -> newTeam.id.asJson)
)
))
apk <- EitherT[Future, AppError, ActualOtoroshiApiKey](otoroshiClient.getApikey(subscription.apiKey.clientId)(otoroshiSettings))
newApk = apk.copy(clientName = s"daikoku-api-key-${api.humanReadableId}-${plan.customName
.getOrElse(plan.typeName)
.urlPathSegmentSanitized}-${newTeam.humanReadableId}-${System
.currentTimeMillis()}-${api.currentVersion.value}",
metadata = apk.metadata + ("daikoku_transfer_to_team_id" -> newTeam.id.value) + ("daikoku_transfer_to_team" -> newTeam.name))
_ <- EitherT[Future, AppError, ActualOtoroshiApiKey](otoroshiClient.updateApiKey(newApk)(otoroshiSettings))
_ <- EitherT.liftF[Future, AppError, Boolean](env.dataStore.notificationRepo.forTenant(tenant).save(
Notification(
id = NotificationId(
Expand Down
9 changes: 2 additions & 7 deletions daikoku/test/daikoku/ApiControllerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1881,13 +1881,8 @@ class ApiControllerSpec()
ownerSubs.length mustBe 1
ownerSubs.head.id mustBe subscription.id

//eventuellement verifier les metadata de l'apk pour voir la team
//tester les cas non passant :
//1: l equipe a deja une souscription et la securité est desactivé
//2: l equipe a deja une souscription (enfant) et la securité est desactivé
//3: l equipe n'a pas acces a l'api
//4: l equipe n'a pas acces a une api enfant
//5: la souscription est enfant
//TODO: verifier le nouveau nom de la subscription

}

"not transfer child subscriptions to another team but parent subscription" in {
Expand Down

0 comments on commit 2ec4585

Please sign in to comment.