From d1e3e819a56bf51a457ac78b551501155e337c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Fri, 5 Sep 2025 08:31:47 +0200 Subject: [PATCH] feature/Add function getCallsLimit v5.1.0 --- .../scala/code/api/v5_1_0/APIMethods510.scala | 47 ++++++- .../code/api/v5_1_0/JSONFactory5.1.0.scala | 75 +++++++++- .../ratelimiting/MappedRateLimiting.scala | 92 ++++++------ .../code/ratelimiting/RateLimiting.scala | 1 + .../code/api/v5_1_0/RateLimitingTest.scala | 132 ++++++++++++++++++ .../code/api/v5_1_0/V510ServerSetup.scala | 12 +- zed/tasks.json | 4 +- 7 files changed, 305 insertions(+), 58 deletions(-) create mode 100644 obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 3d066c754..948c370d9 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -29,7 +29,7 @@ import code.api.v3_1_0._ import code.api.v4_0_0.JSONFactory400.{createAccountBalancesJson, createBalancesJson, createNewCoreBankAccountJson} import code.api.v4_0_0._ import code.api.v5_0_0.JSONFactory500 -import code.api.v5_1_0.JSONFactory510.{createConsentsInfoJsonV510, createConsentsJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson} +import code.api.v5_1_0.JSONFactory510.{createCallLimitJson, createConsentsInfoJsonV510, createConsentsJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson} import code.atmattribute.AtmAttribute import code.bankconnectors.Connector import code.consent.{ConsentRequests, ConsentStatus, Consents, MappedConsent} @@ -39,6 +39,7 @@ import code.loginattempts.LoginAttempt import code.metrics.APIMetrics import code.model.dataAccess.{AuthUser, MappedBankAccount} import code.model.{AppType, Consumer} +import code.ratelimiting.{RateLimiting, RateLimitingDI} import code.regulatedentities.MappedRegulatedEntityProvider import code.userlocks.UserLocksProvider import code.users.Users @@ -3290,6 +3291,50 @@ trait APIMethods510 { } + staticResourceDocs += ResourceDoc( + getCallsLimit, + implementedInApiVersion, + nameOf(getCallsLimit), + "GET", + "/management/consumers/CONSUMER_ID/consumer/call-limits", + "Get Call Limits for a Consumer", + s""" + |Get Calls limits per Consumer. + |${userAuthenticationMessage(true)} + | + |""".stripMargin, + EmptyBody, + callLimitJson, + List( + $UserNotLoggedIn, + InvalidJsonFormat, + InvalidConsumerId, + ConsumerNotFoundByConsumerId, + UserHasMissingRoles, + UpdateConsumerError, + UnknownError + ), + List(apiTagConsumer), + Some(List(canReadCallLimits))) + + + lazy val getCallsLimit: OBPEndpoint = { + case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonGet _ => { + cc => + implicit val ec = EndpointContext(Some(cc)) + for { + // (Full(u), callContext) <- authenticatedAccess(cc) + // _ <- NewStyle.function.hasEntitlement("", cc.userId, canReadCallLimits, callContext) + consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, cc.callContext) + rateLimiting: Option[RateLimiting] <- RateLimitingDI.rateLimiting.vend.findMostRecentRateLimit(consumerId, None, None, None) + rateLimit <- Future(RateLimitingUtil.consumerRateLimitState(consumer.consumerId.get).toList) + } yield { + (createCallLimitJson(consumer, rateLimiting, rateLimit), HttpCode.`200`(cc.callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( updateConsumerRedirectURL, implementedInApiVersion, diff --git a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala index 909d5d83f..1c64a09e5 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala @@ -31,6 +31,7 @@ import code.api.berlin.group.ConstantsBG import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.ConsentAccessJson import code.api.util.APIUtil.{DateWithDay, DateWithSeconds, gitCommit, stringOrNull} import code.api.util.ErrorMessages.MandatoryPropertyIsNotSet +import code.api.util.RateLimitingPeriod.LimitCallPeriod import code.api.util._ import code.api.v1_2_1.BankRoutingJsonV121 import code.api.v1_4_0.JSONFactory1_4_0.{ChallengeJsonV140, LocationJsonV140, MetaJsonV140, TransactionRequestAccountJsonV140, transformToLocationFromV140, transformToMetaFromV140} @@ -38,6 +39,7 @@ import code.api.v2_0_0.TransactionRequestChargeJsonV200 import code.api.v2_1_0.ResourceUserJSON import code.api.v3_0_0.JSONFactory300.{createLocationJson, createMetaJson, transformToAddressFromV300} import code.api.v3_0_0.{AddressJsonV300, OpeningTimesV300} +import code.api.v3_1_0.{CallLimitJson, RateLimit, RedisCallLimitJson} import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400} import code.api.v5_0_0.PostConsentRequestJsonV500 import code.atmattribute.AtmAttribute @@ -45,6 +47,7 @@ import code.atms.Atms.Atm import code.consent.MappedConsent import code.metrics.APIMetric import code.model.Consumer +import code.ratelimiting.RateLimiting import code.users.{UserAttribute, Users} import code.util.Helper.MdcLoggable import code.views.system.{AccountAccess, ViewDefinition, ViewPermission} @@ -147,8 +150,8 @@ case class CheckSystemIntegrityJsonV510( debug_info: Option[String] = None ) -case class ConsentJsonV510(consent_id: String, - jwt: String, +case class ConsentJsonV510(consent_id: String, + jwt: String, status: String, consent_request_id: Option[String], scopes: Option[List[Role]], @@ -466,7 +469,7 @@ case class ConsumerJsonV510(consumer_id: String, certificate_info: Option[CertificateInfoJsonV510], created_by_user: ResourceUserJSON, enabled: Boolean, - created: Date, + created: Date, logo_url: Option[String] ) case class MyConsumerJsonV510(consumer_id: String, @@ -482,7 +485,7 @@ case class MyConsumerJsonV510(consumer_id: String, certificate_info: Option[CertificateInfoJsonV510], created_by_user: ResourceUserJSON, enabled: Boolean, - created: Date, + created: Date, logo_url: Option[String] ) case class ConsumerJsonOnlyForPostResponseV510(consumer_id: String, @@ -682,6 +685,20 @@ case class ViewPermissionJson( extra_data: Option[List[String]] ) +case class CallLimitJson510( + from_date: Date, + to_date: Date, + per_second_call_limit : String, + per_minute_call_limit : String, + per_hour_call_limit : String, + per_day_call_limit : String, + per_week_call_limit : String, + per_month_call_limit : String, + created_at : Date, + updated_at : Date, + current_state: Option[RedisCallLimitJson] + ) + object JSONFactory510 extends CustomJsonFormats with MdcLoggable { def createTransactionRequestJson(tr : TransactionRequest, transactionRequestAttributes: List[TransactionRequestAttributeTrait] ) : TransactionRequestJsonV510 = { @@ -718,7 +735,7 @@ object JSONFactory510 extends CustomJsonFormats with MdcLoggable { def createTransactionRequestJSONs(transactionRequests : List[TransactionRequest], transactionRequestAttributes: List[TransactionRequestAttributeTrait]) : TransactionRequestsJsonV510 = { TransactionRequestsJsonV510( transactionRequests.map( - transactionRequest => + transactionRequest => createTransactionRequestJson(transactionRequest, transactionRequestAttributes) )) } @@ -1259,13 +1276,13 @@ object JSONFactory510 extends CustomJsonFormats with MdcLoggable { if(value == null || value.isEmpty) None else Some(value.split(",").toList) ) } - + def createMinimalAgentsJson(agents: List[Agent]): MinimalAgentsJsonV510 = { MinimalAgentsJsonV510( agents .filter(_.isConfirmedAgent == true) .map(agent => MinimalAgentJsonV510( - agent_id = agent.agentId, + agent_id = agent.agentId, legal_name = agent.legalName, agent_number = agent.number ))) @@ -1306,4 +1323,48 @@ object JSONFactory510 extends CustomJsonFormats with MdcLoggable { ) } + def createCallLimitJson(consumer: Consumer, rateLimiting: Option[RateLimiting], rateLimits: List[((Option[Long], Option[Long]), LimitCallPeriod)]): CallLimitJson510 = { + val redisRateLimit = rateLimits match { + case Nil => None + case _ => + def getInfo(period: RateLimitingPeriod.Value): Option[RateLimit] = { + rateLimits.filter(_._2 == period) match { + case x :: Nil => + x._1 match { + case (Some(x), Some(y)) => Some(RateLimit(Some(x), Some(y))) + case _ => None + + } + case _ => None + } + } + + Some( + RedisCallLimitJson( + getInfo(RateLimitingPeriod.PER_SECOND), + getInfo(RateLimitingPeriod.PER_MINUTE), + getInfo(RateLimitingPeriod.PER_HOUR), + getInfo(RateLimitingPeriod.PER_DAY), + getInfo(RateLimitingPeriod.PER_WEEK), + getInfo(RateLimitingPeriod.PER_MONTH) + ) + ) + } + + CallLimitJson510( + from_date = rateLimiting.map(_.fromDate).orNull, + to_date = rateLimiting.map(_.toDate).orNull, + per_second_call_limit = rateLimiting.map(_.perSecondCallLimit.toString).getOrElse("-1"), + per_minute_call_limit = rateLimiting.map(_.perMinuteCallLimit.toString).getOrElse("-1"), + per_hour_call_limit = rateLimiting.map(_.perHourCallLimit.toString).getOrElse("-1"), + per_day_call_limit = rateLimiting.map(_.perDayCallLimit.toString).getOrElse("-1"), + per_week_call_limit = rateLimiting.map(_.perWeekCallLimit.toString).getOrElse("-1"), + per_month_call_limit = rateLimiting.map(_.perMonthCallLimit.toString).getOrElse("-1"), + created_at = rateLimiting.map(_.createdAt.get).orNull, + updated_at = rateLimiting.map(_.updatedAt.get).orNull, + redisRateLimit + ) + + } + } diff --git a/obp-api/src/main/scala/code/ratelimiting/MappedRateLimiting.scala b/obp-api/src/main/scala/code/ratelimiting/MappedRateLimiting.scala index 6ce5227d3..bf01e1eaa 100644 --- a/obp-api/src/main/scala/code/ratelimiting/MappedRateLimiting.scala +++ b/obp-api/src/main/scala/code/ratelimiting/MappedRateLimiting.scala @@ -101,6 +101,28 @@ object MappedRateLimitingProvider extends RateLimitingProviderTrait { } result } + + def findMostRecentRateLimit(consumerId: String, + bankId: Option[String], + apiVersion: Option[String], + apiName: Option[String]): Future[Option[RateLimiting]] = Future { + findMostRecentRateLimitCommon(consumerId, bankId, apiVersion, apiName) + } + def findMostRecentRateLimitCommon(consumerId: String, + bankId: Option[String], + apiVersion: Option[String], + apiName: Option[String]): Option[RateLimiting] = { + val byConsumerParam = By(RateLimiting.ConsumerId, consumerId) + val byBankParam = bankId.map(v => By(RateLimiting.BankId, v)).getOrElse(NullRef(RateLimiting.BankId)) + val byApiVersionParam = apiVersion.map(v => By(RateLimiting.ApiVersion, v)).getOrElse(NullRef(RateLimiting.ApiVersion)) + val byApiNameParam = apiName.map(v => By(RateLimiting.ApiName, v)).getOrElse(NullRef(RateLimiting.ApiName)) + + RateLimiting.findAll( + byConsumerParam, byBankParam, byApiVersionParam, byApiNameParam, + OrderBy(RateLimiting.updatedAt, Descending) + ).headOption + } + def createOrUpdateConsumerCallLimits(consumerId: String, fromDate: Date, toDate: Date, @@ -113,64 +135,40 @@ object MappedRateLimitingProvider extends RateLimitingProviderTrait { perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[RateLimiting]] = Future { - - def createRateLimit(c: RateLimiting): Box[RateLimiting] = { + + def createOrUpdateRateLimit(c: RateLimiting): Box[RateLimiting] = { tryo { c.FromDate(fromDate) c.ToDate(toDate) - perSecond match { - case Some(v) => c.PerSecondCallLimit(v.toLong) - case None => - } - perMinute match { - case Some(v) => c.PerMinuteCallLimit(v.toLong) - case None => - } - perHour match { - case Some(v) => c.PerHourCallLimit(v.toLong) - case None => - } - perDay match { - case Some(v) => c.PerDayCallLimit(v.toLong) - case None => - } - perWeek match { - case Some(v) => c.PerWeekCallLimit(v.toLong) - case None => - } - perMonth match { - case Some(v) => c.PerMonthCallLimit(v.toLong) - case None => - } - bankId match { - case Some(v) => c.BankId(v) - case None => c.BankId(null) - } - apiName match { - case Some(v) => c.ApiName(v) - case None => c.ApiName(null) - } - apiVersion match { - case Some(v) => c.ApiVersion(v) - case None => c.ApiVersion(null) - } + + perSecond.foreach(v => c.PerSecondCallLimit(v.toLong)) + perMinute.foreach(v => c.PerMinuteCallLimit(v.toLong)) + perHour.foreach(v => c.PerHourCallLimit(v.toLong)) + perDay.foreach(v => c.PerDayCallLimit(v.toLong)) + perWeek.foreach(v => c.PerWeekCallLimit(v.toLong)) + perMonth.foreach(v => c.PerMonthCallLimit(v.toLong)) + + c.BankId(bankId.orNull) + c.ApiName(apiName.orNull) + c.ApiVersion(apiVersion.orNull) c.ConsumerId(consumerId) + + // 👇 bump timestamp for last-write-wins + c.updatedAt(new Date()) + c.saveMe() } } - - val byConsumerParam = By(RateLimiting.ConsumerId, consumerId) - val byBankParam = if(bankId.isDefined) By(RateLimiting.BankId, bankId.get) else NullRef(RateLimiting.BankId) - val byApiVersionParam = if(apiVersion.isDefined) By(RateLimiting.ApiVersion, apiVersion.get) else NullRef(RateLimiting.ApiVersion) - val byApiNameParam = if(apiName.isDefined) By(RateLimiting.ApiName, apiName.get) else NullRef(RateLimiting.ApiName) - val rateLimit = RateLimiting.find(byConsumerParam, byBankParam, byApiVersionParam, byApiNameParam) - val result = rateLimit match { - case Full(limit) => createRateLimit(limit) - case _ => createRateLimit(RateLimiting.create) + val result = findMostRecentRateLimitCommon(consumerId, bankId, apiVersion, apiName) match { + case Some(limit) => createOrUpdateRateLimit(limit) + case None => createOrUpdateRateLimit(RateLimiting.create) } + result } + + } class RateLimiting extends RateLimitingTrait with LongKeyedMapper[RateLimiting] with IdPK with CreatedUpdated { diff --git a/obp-api/src/main/scala/code/ratelimiting/RateLimiting.scala b/obp-api/src/main/scala/code/ratelimiting/RateLimiting.scala index 728da15c0..27fc319c5 100644 --- a/obp-api/src/main/scala/code/ratelimiting/RateLimiting.scala +++ b/obp-api/src/main/scala/code/ratelimiting/RateLimiting.scala @@ -17,6 +17,7 @@ trait RateLimitingProviderTrait { def getAll(): Future[List[RateLimiting]] def getAllByConsumerId(consumerId: String, date: Option[Date] = None): Future[List[RateLimiting]] def getByConsumerId(consumerId: String, apiVersion: String, apiName: String, date: Option[Date] = None): Future[Box[RateLimiting]] + def findMostRecentRateLimit(consumerId: String, bankId: Option[String], apiVersion: Option[String], apiName: Option[String]): Future[Option[RateLimiting]] def createOrUpdateConsumerCallLimits(consumerId: String, fromDate: Date, toDate: Date, diff --git a/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala new file mode 100644 index 000000000..4b9b4f527 --- /dev/null +++ b/obp-api/src/test/scala/code/api/v5_1_0/RateLimitingTest.scala @@ -0,0 +1,132 @@ +/** +Open Bank Project - API +Copyright (C) 2011-2019, TESOBE GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +Email: contact@tesobe.com +TESOBE GmbH +Osloerstrasse 16/17 +Berlin 13359, Germany + +This product includes software developed at +TESOBE (http://www.tesobe.com/) +*/ +package code.api.v5_1_0 + +import code.api.util.APIUtil.OAuth._ +import code.api.util.ApiRole +import code.api.util.ApiRole.CanReadCallLimits +import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn} +import code.api.v4_0_0.CallLimitPostJsonV400 +import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0 +import code.consumer.Consumers +import code.entitlement.Entitlement +import code.setup.PropsReset +import com.github.dwickern.macros.NameOf.nameOf +import com.openbankproject.commons.model.ErrorMessage +import com.openbankproject.commons.util.ApiVersion +import org.scalatest.Tag + +import java.time.format.DateTimeFormatter +import java.time.{ZoneId, ZonedDateTime} +import java.util.Date + +class RateLimitingTest extends V510ServerSetup with PropsReset { + + /** + * Test tags + * Example: To run tests with tag "getPermissions": + * mvn test -D tagsToInclude + * + * This is made possible by the scalatest maven plugin + */ + object ApiVersion400 extends Tag(ApiVersion.v4_0_0.toString) + object ApiVersion510 extends Tag(ApiVersion.v5_1_0.toString) + object ApiCallsLimit extends Tag(nameOf(Implementations5_1_0.getCallsLimit)) + + override def beforeEach() = { + super.beforeEach() + setPropsValues("use_consumer_limits"->"true") + setPropsValues("user_consumer_limit_anonymous_access"->"6000") + } + + val yesterday = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1) + val tomorrow = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(10) + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'") + + val fromDate = Date.from(yesterday.toInstant()) + val toDate = Date.from(tomorrow.toInstant()) + + val callLimitJsonInitial = CallLimitPostJsonV400( + from_date = fromDate, + to_date = toDate, + api_version = None, + api_name = None, + bank_id = None, + per_second_call_limit = "-1", + per_minute_call_limit = "-1", + per_hour_call_limit = "-1", + per_day_call_limit ="-1", + per_week_call_limit = "-1", + per_month_call_limit = "-1" + ) + val callLimitJsonMonth: CallLimitPostJsonV400 = callLimitJsonInitial.copy(per_month_call_limit = "100") + + + feature("Rate Limit - " + ApiCallsLimit + " - " + ApiVersion400) { + + scenario("We will try to get calls limit per minute for a Consumer - unauthorized access", ApiCallsLimit, ApiVersion510) { + When(s"We make a request $ApiVersion510") + val Some((c, _)) = user1 + val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.consumerId.get).getOrElse("") + val request510 = (v5_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "call-limits").GET + val response510 = makeGetRequest(request510) + Then("We should get a 401") + response510.code should equal(401) + And("error should be " + UserNotLoggedIn) + response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) + } + scenario("We will try to get calls limit per minute without a proper Role " + ApiRole.canReadCallLimits, ApiCallsLimit, ApiVersion510) { + When("We make a request v3.1.0 without a Role " + ApiRole.canReadCallLimits) + val Some((c, _)) = user1 + val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.consumerId.get).getOrElse("") + val request510 = (v5_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "call-limits").GET <@ (user1) + val response510 = makeGetRequest(request510) + Then("We should get a 403") + response510.code should equal(403) + And("error should be " + UserHasMissingRoles + CanReadCallLimits) + response510.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanReadCallLimits) + } + scenario("We will try to get calls limit per minute with a proper Role " + ApiRole.canReadCallLimits, ApiCallsLimit, ApiVersion510) { + + When("We make a request v5.1.0 with a Role " + ApiRole.canSetCallLimits) + val response01 = setRateLimiting(user1, callLimitJsonMonth) + Then("We should get a 200") + response01.code should equal(200) + + When(s"We make a request v$ApiVersion510 with a Role " + ApiRole.canReadCallLimits) + val Some((c, _)) = user1 + val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.consumerId.get).getOrElse("") + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanReadCallLimits.toString) + val request510 = (v5_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "call-limits").GET <@ (user1) + val response510 = makeGetRequest(request510) + Then("We should get a 200") + response510.code should equal(200) + response510.body.extract[CallLimitJson510] + + } + + } +} \ No newline at end of file diff --git a/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala b/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala index e25fd43b2..32fa52065 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala @@ -11,8 +11,9 @@ import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140 import code.api.v2_0_0.{BasicAccountsJSON, TransactionRequestBodyJsonV200} import code.api.v3_0_0.ViewJsonV300 import code.api.v3_1_0.{CreateAccountRequestJsonV310, CreateAccountResponseJsonV310, CustomerJsonV310} -import code.api.v4_0_0.{AtmJsonV400, BanksJson400, PostAccountAccessJsonV400, PostViewJsonV400, TransactionRequestWithChargeJSON400} +import code.api.v4_0_0.{AtmJsonV400, BanksJson400, CallLimitPostJsonV400, PostAccountAccessJsonV400, PostViewJsonV400, TransactionRequestWithChargeJSON400} import code.api.v5_0_0.PostCustomerJsonV500 +import code.consumer.Consumers import code.entitlement.Entitlement import code.setup.{APIResponse, DefaultUsers, ServerSetupWithTestData} import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121, CreateViewJson} @@ -32,6 +33,15 @@ trait V510ServerSetup extends ServerSetupWithTestData with DefaultUsers { def dynamicEndpoint_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-endpoint`.toString def dynamicEntity_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-entity`.toString + + def setRateLimiting(consumerAndToken: Option[(Consumer, Token)], putJson: CallLimitPostJsonV400): APIResponse = { + val Some((c, _)) = consumerAndToken + val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.consumerId.get).getOrElse("") + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanSetCallLimits.toString) + val request400 = (v4_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "call-limits").PUT <@ (consumerAndToken) + makePutRequest(request400, write(putJson)) + } + def randomBankId : String = { def getBanksInfo : APIResponse = { val request = v5_1_0_Request / "banks" diff --git a/zed/tasks.json b/zed/tasks.json index 4655b6ea8..a369daf57 100644 --- a/zed/tasks.json +++ b/zed/tasks.json @@ -4,8 +4,8 @@ "command": "mvn", "args": ["jetty:run", "-pl", "obp-api"], "env": { - "MAVEN_OPTS": "-Xss128m --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.math=ALL-UNNAMED" - }, + "MAVEN_OPTS": "-Xss128m --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.math=ALL-UNNAMED --add-opens=java.base/java.util.stream=ALL-UNNAMED --add-opens=java.base/java.util.regex=ALL-UNNAMED" + } "use_new_terminal": true, "allow_concurrent_runs": false, "reveal": "always",