Skip to content

Commit

Permalink
#538 - wip
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinovega committed Aug 8, 2023
1 parent eeb70a8 commit 9c13291
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 31 deletions.
6 changes: 5 additions & 1 deletion daikoku/app/controllers/ApiController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3806,7 +3806,7 @@ class ApiController(
}
}

def createNewPlan(teamId: String, apiId: String, version: String) =
def createPlan(teamId: String, apiId: String, version: String) =
DaikokuAction.async(parse.json) { ctx =>
TeamApiEditorOnly(
AuditTrailEvent(s"@{user.name} has created new plan @{plan.id} for api @{api.name} to @{newTeam.name}")
Expand All @@ -3829,6 +3829,8 @@ class ApiController(
api <- EitherT.fromOptionF[Future, AppError, Api](env.dataStore.apiRepo.forTenant(ctx.tenant)
.findOneNotDeleted(Json.obj("_id" -> apiId, "team" -> team.id.asJson, "currentVersion" -> version)), AppError.ApiNotFound)
updatedPlan <- addProcess(api, newPlan)
plans <- EitherT.liftF(env.dataStore.usagePlanRepo.findByApi(ctx.tenant.id, api))
_ <- updatedPlan.checkCustomName(ctx.tenant, plans)
updatedApi = api.copy(possibleUsagePlans = api.possibleUsagePlans :+ updatedPlan.id)
_ <- EitherT.liftF[Future, AppError, Boolean](env.dataStore.apiRepo.forTenant(ctx.tenant).save(updatedApi))
_ <- EitherT.liftF[Future, AppError, Boolean](env.dataStore.usagePlanRepo.forTenant(ctx.tenant).save(updatedPlan))
Expand Down Expand Up @@ -4001,6 +4003,8 @@ class ApiController(
val value: EitherT[Future, AppError, Result] = for {
api <- EitherT.fromOptionF(env.dataStore.apiRepo.forTenant(ctx.tenant)
.findOneNotDeleted(Json.obj("_id" -> apiId, "team" -> team.id.asJson, "currentVersion" -> version)), AppError.ApiNotFound)
plans <- EitherT.liftF(env.dataStore.usagePlanRepo.findByApi(ctx.tenant.id, api))
_ <- updatedPlan.checkCustomName(ctx.tenant, plans)
oldPlan <- EitherT.fromOptionF(env.dataStore.usagePlanRepo.forTenant(ctx.tenant).findById(planId), AppError.PlanNotFound)
_ <- EitherT.liftF(env.dataStore.subscriptionDemandRepo.forTenant(ctx.tenant)
.updateManyByQuery(
Expand Down
3 changes: 2 additions & 1 deletion daikoku/app/domain/SchemaDefinition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ object SchemaDefinition {
Field("apiReferenceHideForGuest", OptionType(BooleanType), resolve = _.value.apiReferenceHideForGuest),
Field("defaultMessage", OptionType(StringType), resolve = _.value.defaultMessage),
Field("tenantMode", OptionType(StringType), resolve = _.value.tenantMode.map(_.name)),
Field("aggregationApiKeysSecurity", OptionType(BooleanType), resolve = _.value.aggregationApiKeysSecurity)
Field("aggregationApiKeysSecurity", OptionType(BooleanType), resolve = _.value.aggregationApiKeysSecurity),
Field("display", OptionType(StringType), resolve = _.value.display.name)
)
)

Expand Down
11 changes: 11 additions & 0 deletions daikoku/app/domain/apiEntities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,17 @@ sealed trait UsagePlan {
def addSubscriptionStep(step: ValidationStep,
idx: Option[Int] = None): UsagePlan
def removeSubscriptionStep(predicate: ValidationStep => Boolean): UsagePlan
def checkCustomName(tenant: Tenant, plans: Seq[UsagePlan])(implicit ec: ExecutionContext): EitherT[Future, AppError, Unit] = {
val existingNames = plans.collect(_.customName)
.collect { case Some(name) => name }
tenant.display match {
case TenantDisplay.Environment => customName match {
case Some(customName) if tenant.environments.contains(customName) && !existingNames.contains(customName) => EitherT.pure[Future, AppError](())
case _ => EitherT.leftT[Future, Unit](AppError.EntityConflict("Plan custom name"))
}
case TenantDisplay.Default => EitherT.pure[Future, AppError](())
}
}
}

case object UsagePlan {
Expand Down
27 changes: 25 additions & 2 deletions daikoku/app/domain/json.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,17 @@ object json {

override def writes(o: TenantMode): JsValue = JsString(o.name)
}
val TenantDisplayFormat = new Format[TenantDisplay] {
override def reads(json: JsValue): JsResult[TenantDisplay] =
json.asOpt[String].map(_.toLowerCase) match {
case Some("environment") => JsSuccess(TenantDisplay.Environment)
case Some("default") => JsSuccess(TenantDisplay.Default)
case None => JsSuccess(TenantDisplay.Default)
case Some(str) => JsError(s"Bad value for tenant display : $str")
}

override def writes(o: TenantDisplay): JsValue = JsString(o.name)
}
val ApiSubscriptionIdFormat = new Format[ApiSubscriptionId] {
override def reads(json: JsValue): JsResult[ApiSubscriptionId] =
Try {
Expand Down Expand Up @@ -1958,7 +1969,13 @@ object json {
robotTxt = (json \ "robotTxt").asOpt[String],
thirdPartyPaymentSettings = (json \ "thirdPartyPaymentSettings")
.asOpt(SeqThirdPartyPaymentSettingsFormat)
.getOrElse(Seq.empty)
.getOrElse(Seq.empty),
display = (json \ "display").asOpt(TenantDisplayFormat)
.getOrElse(TenantDisplay.Default),
environments = (json \ "environments")
.asOpt[Set[String]]
.getOrElse(Set.empty),
defaultEnvironment = (json \ "defaultEnvironment").asOpt[String]
)
)
} recover {
Expand Down Expand Up @@ -2026,7 +2043,13 @@ object json {
.getOrElse(JsNull)
.as[JsValue],
"thirdPartyPaymentSettings" -> SeqThirdPartyPaymentSettingsFormat.writes(
o.thirdPartyPaymentSettings)
o.thirdPartyPaymentSettings),
"display" -> TenantDisplayFormat.writes(o.display),
"environments" -> JsArray(o.environments.map(JsString.apply).toSeq),
"defaultEnvironment" -> o.defaultEnvironment
.map(JsString.apply)
.getOrElse(JsNull)
.as[JsValue]
)
}
val AuditTrailConfigFormat = new Format[AuditTrailConfig] {
Expand Down
25 changes: 23 additions & 2 deletions daikoku/app/domain/tenantEntities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,22 @@ object TenantMode {
case _ => Some(Default)
}
}
sealed trait TenantDisplay {
def name: String
}

object TenantDisplay {
case object Environment extends TenantDisplay {
def name: String = "environment"
}
case object Default extends TenantDisplay {
def name: String = "default"
}
def apply(name: String): TenantDisplay = name.toLowerCase() match {
case "environment" => Environment
case _ => Default
}
}

sealed trait ThirdPartyPaymentSettings {
def id: ThirdPartyPaymentSettingsId
Expand Down Expand Up @@ -281,7 +297,10 @@ case class Tenant(
tenantMode: Option[TenantMode] = None,
aggregationApiKeysSecurity: Option[Boolean] = None,
robotTxt: Option[String] = None,
thirdPartyPaymentSettings: Seq[ThirdPartyPaymentSettings] = Seq.empty
thirdPartyPaymentSettings: Seq[ThirdPartyPaymentSettings] = Seq.empty,
display: TenantDisplay = TenantDisplay.Default,
environments: Set[String] = Set.empty,
defaultEnvironment: Option[String] = None
) extends CanJson[Tenant] {

override def asJson: JsValue = json.TenantFormat.writes(this)
Expand Down Expand Up @@ -343,7 +362,9 @@ case class Tenant(
"aggregationApiKeysSecurity" -> aggregationApiKeysSecurity
.map(JsBoolean)
.getOrElse(JsBoolean(false))
.as[JsValue]
.as[JsValue],
"display" -> display.name,
"environments" -> JsArray(environments.map(JsString.apply).toSeq)
)
}
def colorTheme(): Html = {
Expand Down
6 changes: 3 additions & 3 deletions daikoku/conf/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</appender>

<logger name="play" level="INFO" />
<logger name="application" level="DEBUG" />
<logger name="application" level="INFO" />
<logger name="MongoDataStore" level="INFO" />
<logger name="MongoTenantAwareRepo" level="INFO" />
<logger name="CommonMongoRepo" level="INFO" />
Expand All @@ -35,12 +35,12 @@
<logger name="audit-actor" level="INFO" />
<logger name="AuditTrailPurgeJob" level="INFO" />
<logger name="otoroshi-reactive-pg-kv" level="INFO" />
<logger name="PostgresDataStore" level="DEBUG" />
<logger name="PostgresDataStore" level="INFO" />
<logger name="otoroshi-reactive-pg-kv" level="INFO" />
<logger name="OtoroshiDeletionJob" level="INFO" />
<logger name="PostgresTenantAwareRepo" level="INFO" />
<logger name="CommonPostgresRepo" level="INFO" />
<logger name="otoroshi-reactive-pg-kv" level="DEBUG" />
<logger name="otoroshi-reactive-pg-kv" level="INFO" />

<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
Expand Down
2 changes: 1 addition & 1 deletion daikoku/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ GET /api/teams/:teamId/apis fr.maif.otoroshi
GET /api/teams/:teamId/apis/:apiId/:version/pages fr.maif.otoroshi.daikoku.ctrls.ApiController.getAllApiDocumentation(teamId, apiId, version)
PUT /api/teams/:teamId/apis/:apiId/:version/pages fr.maif.otoroshi.daikoku.ctrls.ApiController.cloneDocumentation(teamId, apiId, version)
GET /api/categories fr.maif.otoroshi.daikoku.ctrls.ApiController.categories()
POST /api/teams/:teamId/apis/:apiId/:version/plan fr.maif.otoroshi.daikoku.ctrls.ApiController.createNewPlan(teamId, apiId, version)
POST /api/teams/:teamId/apis/:apiId/:version/plan fr.maif.otoroshi.daikoku.ctrls.ApiController.createPlan(teamId, apiId, version)
PUT /api/teams/:teamId/apis/:apiId/:version/plan/:planId fr.maif.otoroshi.daikoku.ctrls.ApiController.updatePlan(teamId, apiId, version, planId)
DELETE /api/teams/:teamId/apis/:apiId/:version/plan/:planId fr.maif.otoroshi.daikoku.ctrls.ApiController.deletePlan(teamId, apiId, version, planId)
PUT /api/teams/:teamId/apis/:id/:version/plan/:planId/_payment fr.maif.otoroshi.daikoku.ctrls.ApiController.setupPayment(teamId, id, version, planId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AuditForm, AuthenticationForm, BucketForm, CustomizationForm, GeneralFo
import { SecurityForm } from './forms/SecurityForm';
import { ThirdPartyPaymentForm } from './forms/ThirdPartyPaymentForm';
import { isError } from '../../../types';
import { DisplayForm } from './forms/DisplayForm';

export const TenantEditComponent = ({ tenantId, fromDaikokuAdmin }: { tenantId: string, fromDaikokuAdmin?: boolean }) => {
const { translate } = useContext(I18nContext)
Expand Down Expand Up @@ -115,6 +116,15 @@ export const TenantEditComponent = ({ tenantId, fromDaikokuAdmin }: { tenantId:
</>
}
/>
<Route
path="/display-mode"
element={
<>
{fromDaikokuAdmin && <h1>{data?.name} - {translate('DisplayMode')}</h1>}
<DisplayForm tenant={data} updateTenant={updateTenant} />
</>
}
/>
</Routes>
)
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Form, Schema, constraints, format, type } from "@maif/react-forms";
import { useContext } from "react";

import { I18nContext } from "../../../../contexts/i18n-context";
import { ITenantFull } from "../../../../types";
import { UseMutationResult } from "@tanstack/react-query";

type UpdateFormProps = {
tenant: ITenantFull
updateTenant: UseMutationResult<any, unknown, ITenantFull, unknown>
}
export const DisplayForm = (props: UpdateFormProps) => {
const { translate } = useContext(I18nContext);

const schema: Schema = {
display: {
type: type.string,
format: format.buttonsSelect,
options: [
{value: 'environment', label: translate('display.environment.label')},
{value: 'default', label: translate('display.default.label')},
],
label: translate('environment-mode.is-private.label'),
help: translate('environment-mode.is-private.help')
},
//TODO: draw a custom component with is default flag
environments: {
type: type.string,
array: true,
label: translate('environment-mode.environments.label'),
help: translate('environment-mode.environments.help'),
visible: ({ rawValues }) => rawValues.isPrivate,
constraints: [
constraints.required('constraints.required.value')
]
}
}

return (
<Form
schema={schema}
onSubmit={(updatedTenant) => props.updateTenant.mutateAsync(updatedTenant)}
value={props.tenant}
options={{
actions: {
submit: { label: translate('Save') }
}
}}
/>
)
}
Loading

0 comments on commit 9c13291

Please sign in to comment.