Skip to content

Commit

Permalink
Everything is compiling but...
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinovega committed Jul 26, 2023
1 parent 1ffb6c6 commit 06907d9
Show file tree
Hide file tree
Showing 25 changed files with 1,214 additions and 1,042 deletions.
201 changes: 127 additions & 74 deletions daikoku/app/controllers/ApiController.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
package fr.maif.otoroshi.daikoku.ctrls

import akka.NotUsed
import akka.http.scaladsl.util.FastFuture
import akka.stream.Materializer
import akka.stream.scaladsl.{Flow, JsonFraming, Sink, Source}
import akka.util.ByteString
import akka.{Done, NotUsed}
import cats.Id
import cats.data.EitherT
import cats.implicits.{catsSyntaxOptionId, toTraverseOps}
import com.auth0.jwt.JWT
import controllers.AppError
import controllers.AppError._
import fr.maif.otoroshi.daikoku.actions.{DaikokuAction, DaikokuActionContext, DaikokuActionMaybeWithGuest}
import fr.maif.otoroshi.daikoku.audit.AuditTrailEvent
import fr.maif.otoroshi.daikoku.ctrls.authorizations.async._
import fr.maif.otoroshi.daikoku.domain.NotificationAction.{ApiAccess, ApiSubscriptionDemand}
import fr.maif.otoroshi.daikoku.domain.SubscriptionDemandState.{InProgress, Waiting}
import fr.maif.otoroshi.daikoku.domain.UsagePlanVisibility.Private
import fr.maif.otoroshi.daikoku.domain._
import fr.maif.otoroshi.daikoku.domain.json._
Expand All @@ -24,8 +21,7 @@ import fr.maif.otoroshi.daikoku.logger.AppLogger
import fr.maif.otoroshi.daikoku.utils.Cypher.decrypt
import fr.maif.otoroshi.daikoku.utils.RequestImplicits.EnhancedRequestHeader
import fr.maif.otoroshi.daikoku.utils.StringImplicits.BetterString
import fr.maif.otoroshi.daikoku.utils.future.EnhancedObject
import fr.maif.otoroshi.daikoku.utils.{ApiService, DeletionService, IdGenerator, OtoroshiClient, Translator}
import fr.maif.otoroshi.daikoku.utils._
import jobs.{ApiKeyStatsJob, OtoroshiVerifierJob}
import org.joda.time.DateTime
import play.api.Logger
Expand All @@ -36,8 +32,6 @@ import play.api.libs.streams.Accumulator
import play.api.mvc._
import reactivemongo.bson.BSONObjectID

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import scala.concurrent.Future
import scala.util.{Failure, Success, Try}

Expand Down Expand Up @@ -340,12 +334,20 @@ class ApiController(
def getApi(api: Api, ctx: DaikokuActionContext[AnyContent]) = {
import cats.implicits._

val r: EitherT[Future, Result, Result] = for {
myTeams <- EitherT.liftF(
env.dataStore.teamRepo.myTeams(ctx.tenant, ctx.user))
error: EitherT[Future, Result, Seq[Notification]] = EitherT
.leftT[Future, Seq[Notification]](AppError.render(ApiNotFound))
value: EitherT[Future, Nothing, Seq[Notification]] = EitherT.liftF(
def control(myTeams: Seq[Team]): EitherT[Future, AppError, Unit] = {
if ((api.visibility == ApiVisibility.Public || ctx.user.isDaikokuAdmin || (api.authorizedTeams :+ api.team)
.intersect(myTeams.map(_.id))
.nonEmpty) && (api.isPublished || myTeams.exists(_.id == api.team))) {
EitherT.pure[Future, AppError](())
} else {
EitherT.leftT[Future, Unit](AppError.ApiUnauthorized)
}
}

for {
myTeams <- EitherT.liftF[Future, AppError, Seq[Team]](env.dataStore.teamRepo.myTeams(ctx.tenant, ctx.user))
_ <- control(myTeams)
pendingRequests <- EitherT.liftF[Future, AppError, Seq[Notification]](
env.dataStore.notificationRepo
.forTenant(ctx.tenant.id)
.findNotDeleted(
Expand All @@ -358,12 +360,7 @@ class ApiController(
)
)
)
adminTeam <- EitherT.fromOptionF(
env.dataStore.teamRepo.forTenant(ctx.tenant).findByIdNotDeleted(api.team),
AppError.TeamNotFound.render()
)
pendingRequests <- value
subscriptions <- EitherT.liftF(
subscriptions <- EitherT.liftF[Future, AppError, Seq[ApiSubscription]](
env.dataStore.apiSubscriptionRepo
.forTenant(ctx.tenant.id)
.findNotDeleted(
Expand All @@ -374,50 +371,75 @@ class ApiController(
)
)
} yield {
if ((api.visibility == ApiVisibility.Public || ctx.user.isDaikokuAdmin || (api.authorizedTeams :+ api.team)
.intersect(myTeams.map(_.id))
.nonEmpty) && (api.isPublished || myTeams.exists(_.id == api.team))) {
val betterApi = api
.asJson
.as[JsObject] ++ Json.obj(
"pendingRequests" -> JsArray(
pendingRequests.map(_.asJson)
)
) ++ Json.obj(
"subscriptions" -> JsArray(subscriptions.map(_.asSimpleJson))
val betterApi = api
.asJson
.as[JsObject] ++ Json.obj(
"pendingRequests" -> JsArray(
pendingRequests.map(_.asJson)
)
ctx.setCtxValue("api.name", api.name)
Ok(
if (ctx.tenant.apiReferenceHideForGuest
.getOrElse(true) && ctx.user.isGuest) betterApi - "swagger"
else betterApi
)
} else {
Unauthorized(
Json.obj(
"error" -> "You're not authorized on this api",
"status" -> 401,
"visibility" -> api.visibility.name
)
)
}
}
) ++ Json.obj(
"subscriptions" -> JsArray(subscriptions.map(_.asSimpleJson))
)
ctx.setCtxValue("api.name", api.name)

if (ctx.tenant.apiReferenceHideForGuest
.getOrElse(true) && ctx.user.isGuest) betterApi - "swagger"
else betterApi

r.value.map(_.merge)
}
}

def getVisibleApiWithId(apiId: String) =
DaikokuActionMaybeWithGuest.async { ctx =>
UberPublicUserAccess(
AuditTrailEvent("@{user.name} is accessing visible api @{api.name}")
)(ctx) {
env.dataStore.apiRepo
.forTenant(ctx.tenant)
.findByIdOrHrId(apiId)
.flatMap {
case None => ApiNotFound.renderF()
case Some(api) => getApi(api, ctx)

(for {
api <- EitherT.fromOptionF(env.dataStore.apiRepo
.forTenant(ctx.tenant)
.findByIdOrHrId(apiId), AppError.ApiNotFound)
betterApi <- getApi(api, ctx)
} yield {
ctx.setCtxValue("api.name", api.name)
Ok(betterApi)
})
.leftMap(_.render())
.merge
}
}

def getVisiblePlan(apiId: String, version: String, planId: String) =
DaikokuActionMaybeWithGuest.async { ctx =>
UberPublicUserAccess(
AuditTrailEvent("@{user.name} is accessing visible plan @{plan.name}")
)(ctx) {

def control(api: Api, myTeams: Seq[Team], plan: UsagePlan): EitherT[Future, AppError, Unit] = {
if ((api.visibility == ApiVisibility.Public || ctx.user.isDaikokuAdmin || (api.authorizedTeams :+ api.team)
.intersect(myTeams.map(_.id))
.nonEmpty) && (api.isPublished || myTeams.exists(_.id == api.team))) {

if (plan.visibility == UsagePlanVisibility.Public || ctx.user.isDaikokuAdmin || (plan.authorizedTeams :+ api.team)
.intersect(myTeams.map(_.id))
.nonEmpty) {
EitherT.pure[Future, AppError](())
} else {
EitherT.leftT[Future, Unit](AppError.PlanUnauthorized)
}
} else {
EitherT.leftT[Future, Unit](AppError.ApiUnauthorized)
}
}

(for {
api <- EitherT.fromOptionF(env.dataStore.apiRepo.findByVersion(ctx.tenant, apiId, version), AppError.ApiNotFound)
plan <- EitherT.fromOptionF(env.dataStore.usagePlanRepo.forTenant(ctx.tenant).findById(planId), AppError.PlanNotFound)
myTeams <- EitherT.liftF(env.dataStore.teamRepo.myTeams(ctx.tenant, ctx.user))
_ <- control(api, myTeams, plan)
} yield Ok(plan.asJson))
.leftMap(_.render())
.merge
}
}

Expand All @@ -426,12 +448,16 @@ class ApiController(
UberPublicUserAccess(
AuditTrailEvent("@{user.name} is accessing visible api @{api.name}")
)(ctx) {
env.dataStore.apiRepo
.findByVersion(ctx.tenant, humanReadableId, version)
.flatMap {
case None => FastFuture.successful(AppError.render(ApiNotFound))
case Some(api) => getApi(api, ctx)
}
(for {
api <- EitherT.fromOptionF(env.dataStore.apiRepo
.findByVersion(ctx.tenant, humanReadableId, version), AppError.ApiNotFound)
betterApi <- getApi(api, ctx)
} yield {
ctx.setCtxValue("api.name", api.name)
Ok(betterApi)
})
.leftMap(_.render())
.merge
}
}

Expand Down Expand Up @@ -1140,10 +1166,11 @@ class ApiController(
NotFound(Json.obj("error" -> "apiSubscription not found"))
)
case Some(subscription) =>
val updatedSubscription = subscription.copy(customName = Some(customName))
env.dataStore.apiSubscriptionRepo
.forTenant(ctx.tenant)
.save(subscription.copy(customName = Some(customName)))
.map(done => Ok(Json.obj("done" -> done)))
.save(updatedSubscription)
.map(_ => Ok(updatedSubscription.asSafeJson))
}
}
}
Expand Down Expand Up @@ -1203,6 +1230,7 @@ class ApiController(
sub: ApiSubscription,
parentSub: Option[ApiSubscription]
): Future[JsValue] = {
val name: String = plan.customName.getOrElse(plan.typeName)
val r = sub
.asAuthorizedJson(
teamPermission,
Expand All @@ -1211,6 +1239,7 @@ class ApiController(
)
.as[JsObject] ++
Json.obj("planType" -> plan.typeName) ++
Json.obj("planName" -> name) ++
Json.obj("apiName" -> api.name) ++
Json.obj("_humanReadableId" -> api.humanReadableId) ++
Json.obj("parentUp" -> false)
Expand Down Expand Up @@ -3620,18 +3649,42 @@ class ApiController(
AuditTrailEvent(
s"@{user.name} has requested all plan of api @{api.id} with @{team.name} - @{team.id}"
)
)(teamId, ctx) { _ =>
env.dataStore.apiRepo
.forTenant(ctx.tenant.id)
.find(
Json.obj(
"_humanReadableId" -> apiId,
"currentVersion" -> Json.obj("$ne" -> version)
)
)
.flatMap { apis =>
FastFuture.successful(Ok(SeqApiFormat.writes(apis)))
}
)(teamId, ctx) { team =>

(for {
api <- EitherT.fromOptionF[Future, AppError, Api](env.dataStore.apiRepo.forTenant(ctx.tenant)
.findOne(Json.obj("_humanReadableId" -> apiId,
"currentVersion" -> Json.obj("$ne" -> version))), AppError.ApiNotFound)
_ <- if (api.team != team.id) EitherT.leftT[Future, Unit](AppError.ApiNotFound) else EitherT.pure[Future, AppError](())
plans <- EitherT.liftF[Future, AppError, Seq[UsagePlan]](env.dataStore.usagePlanRepo.findByApi(ctx.tenant.id, api))
} yield Ok(json.SeqUsagePlanFormat.writes(plans)))
.leftMap(_.render())
.merge
}
}

def getPlan(teamId: String, apiId: String, version: String, planId: String) =
DaikokuAction.async { ctx =>
TeamApiEditorOnly(
AuditTrailEvent(s"@{user.name} get plan of api @{api.id} with @{team.name} - @{team.id}")
)(teamId, ctx) { team =>

def controlApiAndPlan(api: Api): EitherT[Future, AppError, Unit] = {
if (api.team != team.id || api.possibleUsagePlans.forall(p => p.value != planId))
EitherT.leftT[Future, Unit](AppError.PlanNotFound)
else
EitherT.pure[Future, AppError](())
}

(for {
api <- EitherT.fromOptionF[Future, AppError, Api](env.dataStore.apiRepo.forTenant(ctx.tenant)
.findOne(Json.obj("_humanReadableId" -> apiId,
"currentVersion" -> Json.obj("$ne" -> version))), AppError.ApiNotFound)
_ <- controlApiAndPlan(api)
plan <- EitherT.fromOptionF[Future, AppError, UsagePlan](env.dataStore.usagePlanRepo.forTenant(ctx.tenant).findById(planId), AppError.PlanNotFound)
} yield Ok(plan.asJson))
.leftMap(_.render())
.merge
}
}

Expand Down
12 changes: 3 additions & 9 deletions daikoku/app/domain/apiEntities.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package fr.maif.otoroshi.daikoku.domain

import akka.http.scaladsl.util.FastFuture
import cats.data.EitherT
import cats.syntax.option._
import fr.maif.otoroshi.daikoku.domain.json.{
SeqIssueIdFormat,
SeqPostIdFormat,
SeqTeamIdFormat,
SetApiTagFormat,
TeamFormat,
TeamIdFormat,
UsagePlanFormat
}
import controllers.AppError
import fr.maif.otoroshi.daikoku.domain.json.{SeqIssueIdFormat, SeqPostIdFormat, SeqTeamIdFormat, SetApiTagFormat, TeamFormat, TeamIdFormat, UsagePlanFormat}
import fr.maif.otoroshi.daikoku.env.Env
import fr.maif.otoroshi.daikoku.utils.{IdGenerator, ReplaceAllWith}
import fr.maif.otoroshi.daikoku.utils.StringImplicits.BetterString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ class PostgresDataStore(configuration: Configuration, env: Env, pgPool: PgPool)
"subscription_demands" -> true,
"step_validators" -> true,
"usage_plans" -> true
)xw
)

private lazy val poolOptions: PoolOptions = new PoolOptions()
.setMaxSize(configuration.get[Int]("daikoku.postgres.poolSize"))
Expand Down
20 changes: 4 additions & 16 deletions daikoku/app/utils/ApiService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,7 @@ class ApiService(env: Env,
.forTenant(tenant.id)
.save(subscription)
)
} yield {
Json.obj("done" -> true,
"subscription" -> subscription.asSafeJson)
}
} yield subscription.asSafeJson.as[JsObject]

r.value
}
Expand Down Expand Up @@ -465,10 +462,7 @@ class ApiService(env: Env,
.forTenant(tenant.id)
.save(updatedSubscription)
)
} yield {
Json.obj("done" -> true,
"subscription" -> subscription.copy(enabled = enabled).asJson)
}
} yield updatedSubscription.asSafeJson.as[JsObject]

r.value
}
Expand Down Expand Up @@ -552,10 +546,7 @@ class ApiService(env: Env,
tenant.mailer.send(title, Seq(admin.email), body, tenant)
}).flatten
})))
} yield {
Json.obj("done" -> true,
"subscription" -> updatedSubscription.asJson)
}
} yield updatedSubscription.asSafeJson.as[JsObject]
r.value
}
}
Expand Down Expand Up @@ -602,10 +593,7 @@ class ApiService(env: Env,
.forTenant(tenant.id)
.findById(subscription.id)
)
} yield {
Json.obj("done" -> true,
"subscription" -> updatedSubscription.get.asJson)
}
} yield Json.obj("subscription" -> updatedSubscription.get.asSafeJson)
r.value
}
}
Expand Down
2 changes: 2 additions & 0 deletions daikoku/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ GET /api/me/notifications/all fr.maif.otoroshi.daikoku
GET /api/me/notifications/unread-count fr.maif.otoroshi.daikoku.ctrls.NotificationController.myUnreadNotificationsCount()

GET /api/me/visible-apis/:humanReadableId/:version fr.maif.otoroshi.daikoku.ctrls.ApiController.getVisibleApi(humanReadableId, version)
GET /api/me/visible-apis/:apiId/:version/plan/:planId fr.maif.otoroshi.daikoku.ctrls.ApiController.getVisiblePlan(apiId, version, planId)
GET /api/me/visible-apis/:id fr.maif.otoroshi.daikoku.ctrls.ApiController.getVisibleApiWithId(id)
GET /api/me/teams/:teamId/visible-apis/:apiId/:version fr.maif.otoroshi.daikoku.ctrls.ApiController.getTeamVisibleApis(teamId, apiId, version)
GET /api/apis/:apiId/_root fr.maif.otoroshi.daikoku.ctrls.ApiController.getRootApi(apiId)
Expand Down Expand Up @@ -121,6 +122,7 @@ PUT /api/teams/:teamId/apis/:apiId/issues/:issueId fr.maif.otoroshi
POST /api/teams/:teamId/apis/:apiId/versions fr.maif.otoroshi.daikoku.ctrls.ApiController.createVersion(teamId, apiId)
GET /api/teams/:teamId/apis/:apiId/versions fr.maif.otoroshi.daikoku.ctrls.ApiController.getAllApiVersions(teamId, apiId)
GET /api/teams/:teamId/apis/:apiId/:version/plans fr.maif.otoroshi.daikoku.ctrls.ApiController.getAllPlan(teamId, apiId, version)
GET /api/teams/:teamId/apis/:apiId/:version/plans/:planId fr.maif.otoroshi.daikoku.ctrls.ApiController.getPlan(teamId, apiId, version, planId)
POST /api/teams/:teamId/apis/:apiId/plans fr.maif.otoroshi.daikoku.ctrls.ApiController.clonePlan(teamId, apiId)
GET /api/teams/:teamId/apis/:apiId/:version/access fr.maif.otoroshi.daikoku.ctrls.ApiController.getMyTeamsStatusAccess(teamId, apiId, version)
GET /api/teams/:teamId/subscribed-apis fr.maif.otoroshi.daikoku.ctrls.ApiController.subscribedApis(teamId)
Expand Down
Loading

0 comments on commit 06907d9

Please sign in to comment.