mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 15:27:01 +00:00
Merge pull request #1092 from constantine2nd/develop
Added getCallsLimit endpoint
This commit is contained in:
commit
b8384ea8d5
@ -642,7 +642,7 @@ def filterResourceDocs(allResources: List[ResourceDoc], showCore: Option[Boolean
|
||||
cc =>
|
||||
val apiDetails: JValue = {
|
||||
val hostedBy = new HostedBy("Dummy Org", "contact@example.com", "12345", "http://www.example.com")
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion, apiVersionStatus, gitCommit, "dummy-connector", hostedBy, Akka(APIUtil.akkaSanityCheck()))
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion, apiVersionStatus, gitCommit, "dummy-connector", hostedBy, Akka(APIUtil.akkaSanityCheck()), None)
|
||||
Extraction.decompose(apiInfoJSON)
|
||||
}
|
||||
|
||||
|
||||
@ -441,6 +441,8 @@ object SwaggerDefinitionsJSON {
|
||||
val akka = Akka(
|
||||
remote_data_secret_matched = Option(true)
|
||||
)
|
||||
|
||||
val rateLimiting = Option(RateLimiting(true, Option(true)))
|
||||
|
||||
val apiInfoJSON = APIInfoJSON(
|
||||
version = "String",
|
||||
@ -448,7 +450,8 @@ object SwaggerDefinitionsJSON {
|
||||
git_commit = "String",
|
||||
connector = "String",
|
||||
hosted_by = hostedBy,
|
||||
akka = akka
|
||||
akka = akka,
|
||||
rate_limiting = rateLimiting
|
||||
)
|
||||
|
||||
/* val aggregateMetricsJSON = AggregateMetricJSON(
|
||||
|
||||
@ -169,8 +169,11 @@ object ApiRole {
|
||||
case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canReadUserLockedStatus = CanReadUserLockedStatus()
|
||||
|
||||
case class CanSetCallLimit (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canSetCallLimit = CanSetCallLimit()
|
||||
case class CanSetCallLimits(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canSetCallLimits = CanSetCallLimits()
|
||||
|
||||
case class CanReadCallLimits(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canReadCallLimits = CanReadCallLimits()
|
||||
|
||||
case class CanCheckFundsAvailable (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canCheckFundsAvailable = CanCheckFundsAvailable()
|
||||
@ -235,7 +238,8 @@ object ApiRole {
|
||||
canDeleteScopeAtAnyBank ::
|
||||
canDeleteScopeAtOneBank ::
|
||||
canUnlockUser ::
|
||||
canSetCallLimit ::
|
||||
canSetCallLimits ::
|
||||
canReadCallLimits ::
|
||||
canReadUserLockedStatus ::
|
||||
canCheckFundsAvailable ::
|
||||
canCreateWebHook ::
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package code.api.util
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import code.api.util.LimitCallPeriod.LimitCallPeriod
|
||||
import code.util.Helper.MdcLoggable
|
||||
import net.liftweb.util.Props
|
||||
@ -60,6 +62,17 @@ object LimitCallsUtil extends MdcLoggable {
|
||||
new Jedis(url, port)
|
||||
}
|
||||
|
||||
def isRedisAvailable() = {
|
||||
try {
|
||||
val uuid = UUID.randomUUID().toString()
|
||||
jedis.connect()
|
||||
jedis.set(uuid, "10")
|
||||
jedis.exists(uuid) == true
|
||||
} catch {
|
||||
case e : Throwable => false
|
||||
}
|
||||
}
|
||||
|
||||
private def createUniqueKey(consumerKey: String, period: LimitCallPeriod) = consumerKey + LimitCallPeriod.toString(period)
|
||||
|
||||
def underConsumerLimits(consumerKey: String, period: LimitCallPeriod, limit: Long): Boolean = {
|
||||
|
||||
@ -68,6 +68,7 @@ object NewStyle {
|
||||
(nameOf(Implementations3_1_0.getBadLoginStatus), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.unlockUser), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.callsLimit), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.getCallsLimit), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.checkFundsAvailable), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.getConsumer), ApiVersion.v3_1_0.toString),
|
||||
(nameOf(Implementations3_1_0.getConsumersForCurrentUser), ApiVersion.v3_1_0.toString),
|
||||
|
||||
@ -2,12 +2,13 @@ package code.api.v1_2_1
|
||||
|
||||
import java.net.URL
|
||||
import java.util.UUID.randomUUID
|
||||
|
||||
import com.tesobe.CacheKeyFromArguments
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
|
||||
import code.api.cache.Caching
|
||||
import code.api.util.APIUtil._
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.{APIUtil, ApiVersion, CallContext, ErrorMessages}
|
||||
import code.api.util._
|
||||
import code.bankconnectors._
|
||||
import code.metadata.comments.Comments
|
||||
import code.metadata.counterparties.Counterparties
|
||||
@ -34,7 +35,7 @@ trait APIMethods121 {
|
||||
self: RestHelper =>
|
||||
|
||||
val apiMethods121GetTransactionsTTL = APIUtil.getPropsValue("connector.cache.ttl.seconds.APIMethods121.getTransactions", "0").toInt * 1000 // Miliseconds
|
||||
|
||||
|
||||
// helper methods begin here
|
||||
|
||||
private def privateBankAccountsListToJson(bankAccounts: List[BankAccount], privateViewsUserCanAccess: List[View]): JValue = {
|
||||
@ -50,7 +51,7 @@ trait APIMethods121 {
|
||||
val accounts = new AccountsJSON(accJson)
|
||||
Extraction.decompose(accounts)
|
||||
}
|
||||
|
||||
|
||||
private def publicBankAccountsListToJson(bankAccounts: List[BankAccount], publicViews: List[View]): JValue = {
|
||||
val accJson : List[AccountJSON] = bankAccounts.map( account => {
|
||||
val viewsAvailable : List[ViewJSONV121] =
|
||||
@ -60,7 +61,7 @@ trait APIMethods121 {
|
||||
.distinct
|
||||
JSONFactory.createAccountJSON(account,viewsAvailable)
|
||||
})
|
||||
|
||||
|
||||
val accounts = new AccountsJSON(accJson)
|
||||
Extraction.decompose(accounts)
|
||||
}
|
||||
@ -90,9 +91,10 @@ trait APIMethods121 {
|
||||
val organisationWebsite = APIUtil.getPropsValue("organisation_website", "https://www.tesobe.com")
|
||||
|
||||
val connector = APIUtil.getPropsValue("connector").openOrThrowException("no connector set")
|
||||
val rateLimiting = RateLimiting(LimitCallsUtil.useConsumerLimits, Some(LimitCallsUtil.isRedisAvailable()))
|
||||
|
||||
val hostedBy = new HostedBy(organisation, email, phone, organisationWebsite)
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion.vDottedApiVersion(), apiVersionStatus, gitCommit, connector, hostedBy, Akka(APIUtil.akkaSanityCheck()))
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion.vDottedApiVersion(), apiVersionStatus, gitCommit, connector, hostedBy, Akka(APIUtil.akkaSanityCheck()), Some(rateLimiting))
|
||||
Extraction.decompose(apiInfoJSON)
|
||||
}
|
||||
apiDetails
|
||||
|
||||
@ -42,7 +42,8 @@ case class APIInfoJSON(
|
||||
git_commit : String,
|
||||
connector : String,
|
||||
hosted_by : HostedBy,
|
||||
akka: Akka
|
||||
akka: Akka,
|
||||
rate_limiting: Option[RateLimiting]
|
||||
)
|
||||
case class HostedBy(
|
||||
organisation : String,
|
||||
@ -51,6 +52,8 @@ case class HostedBy(
|
||||
organisation_website: String
|
||||
)
|
||||
case class Akka(remote_data_secret_matched: Option[Boolean])
|
||||
case class RateLimiting(enabled: Boolean, redis_available: Option[Boolean])
|
||||
|
||||
case class ErrorMessage(
|
||||
error : String
|
||||
)
|
||||
|
||||
@ -744,7 +744,7 @@ trait APIMethods140 extends MdcLoggable with APIMethods130 with APIMethods121{
|
||||
cc =>
|
||||
val apiDetails: JValue = {
|
||||
val hostedBy = new HostedBy("Dummy Org", "contact@example.com", "12345", "https://www.example.com")
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion.vDottedApiVersion, apiVersionStatus, gitCommit, "DUMMY", hostedBy, Akka(APIUtil.akkaSanityCheck()))
|
||||
val apiInfoJSON = new APIInfoJSON(apiVersion.vDottedApiVersion, apiVersionStatus, gitCommit, "DUMMY", hostedBy, Akka(APIUtil.akkaSanityCheck()), None)
|
||||
Extraction.decompose(apiInfoJSON)
|
||||
}
|
||||
|
||||
|
||||
@ -544,15 +544,15 @@ trait APIMethods310 {
|
||||
),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
List(apiTagConsumer),
|
||||
Some(List(canSetCallLimit)))
|
||||
Some(List(canSetCallLimits)))
|
||||
|
||||
lazy val callsLimit : OBPEndpoint = {
|
||||
case "management" :: "consumers" :: consumerId :: "consumer" :: "calls_limit" :: Nil JsonPut json -> _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- extractCallContext(UserNotLoggedIn, cc)
|
||||
_ <- Helper.booleanToFuture(failMsg = UserHasMissingRoles + CanSetCallLimit) {
|
||||
hasEntitlement("", u.userId, canSetCallLimit)
|
||||
_ <- Helper.booleanToFuture(failMsg = UserHasMissingRoles + CanSetCallLimits) {
|
||||
hasEntitlement("", u.userId, canSetCallLimits)
|
||||
}
|
||||
postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CallLimitJson ", 400, callContext) {
|
||||
json.extract[CallLimitJson]
|
||||
@ -578,6 +578,53 @@ trait APIMethods310 {
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getCallsLimit,
|
||||
implementedInApiVersion,
|
||||
"getCallsLimit",
|
||||
"GET",
|
||||
"/management/consumers/CONSUMER_ID/consumer/calls_limit",
|
||||
"Get Calls' Limit for a Consumer",
|
||||
s"""
|
||||
|Get calls' limit per Consumer.
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""".stripMargin,
|
||||
callLimitJson,
|
||||
callLimitJson,
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
InvalidJsonFormat,
|
||||
InvalidConsumerId,
|
||||
ConsumerNotFoundByConsumerId,
|
||||
UserHasMissingRoles,
|
||||
UpdateConsumerError,
|
||||
UnknownError
|
||||
),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
List(apiTagConsumer),
|
||||
Some(List(canSetCallLimits)))
|
||||
|
||||
lazy val getCallsLimit : OBPEndpoint = {
|
||||
case "management" :: "consumers" :: consumerId :: "consumer" :: "calls_limit" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- extractCallContext(UserNotLoggedIn, cc)
|
||||
_ <- Helper.booleanToFuture(failMsg = UserHasMissingRoles + CanReadCallLimits) {
|
||||
hasEntitlement("", u.userId, canReadCallLimits)
|
||||
}
|
||||
consumerIdToLong <- NewStyle.function.tryons(s"$InvalidConsumerId", 400, callContext) {
|
||||
consumerId.toLong
|
||||
}
|
||||
consumer <- Consumers.consumers.vend.getConsumerByPrimaryIdFuture(consumerIdToLong) map {
|
||||
unboxFullOrFail(_, callContext, ConsumerNotFoundByConsumerId, 400)
|
||||
}
|
||||
} yield {
|
||||
(createCallLimitJson(consumer), callContext.map(_.copy(httpCode = Some(200))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -291,6 +291,7 @@ object OBPAPI3_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
|
||||
Implementations3_1_0.getBadLoginStatus ::
|
||||
Implementations3_1_0.unlockUser ::
|
||||
Implementations3_1_0.callsLimit ::
|
||||
Implementations3_1_0.getCallsLimit ::
|
||||
Implementations3_1_0.checkFundsAvailable ::
|
||||
// Implementations3_1_0.getConsumer ::
|
||||
Implementations3_1_0.getConsumersForCurrentUser ::
|
||||
|
||||
@ -2,7 +2,7 @@ package code.api.v3_1_0
|
||||
|
||||
import code.api.ErrorMessage
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.CanSetCallLimit
|
||||
import code.api.util.ApiRole.{CanReadCallLimits, CanSetCallLimits}
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
|
||||
import code.api.util.{APIUtil, ApiRole, ApiVersion}
|
||||
import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
|
||||
@ -23,6 +23,7 @@ class RateLimitTest extends V310ServerSetup {
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v3_1_0.toString)
|
||||
object ApiEndpoint extends Tag(nameOf(Implementations3_1_0.callsLimit))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations3_1_0.getCallsLimit))
|
||||
|
||||
val callLimitJson1 = CallLimitJson(
|
||||
per_minute_call_limit = "-1",
|
||||
@ -39,7 +40,7 @@ class RateLimitTest extends V310ServerSetup {
|
||||
per_month_call_limit = "-1"
|
||||
)
|
||||
|
||||
feature("Rate Limit - v3.1.0")
|
||||
feature("Rate Limit - " + ApiEndpoint + " - " + VersionOfApi)
|
||||
{
|
||||
|
||||
scenario("We will try to set calls limit per minute for a Consumer - unauthorized access", ApiEndpoint, VersionOfApi) {
|
||||
@ -53,36 +54,34 @@ class RateLimitTest extends V310ServerSetup {
|
||||
And("error should be " + UserNotLoggedIn)
|
||||
response310.body.extract[ErrorMessage].error should equal (UserNotLoggedIn)
|
||||
}
|
||||
scenario("We will try to set calls limit per minute without a proper Role " + ApiRole.canGetConsumers, ApiEndpoint, VersionOfApi) {
|
||||
When("We make a request v3.1.0 without a Role " + ApiRole.canSetCallLimit)
|
||||
scenario("We will try to set calls limit per minute without a proper Role " + ApiRole.canSetCallLimits, ApiEndpoint, VersionOfApi) {
|
||||
When("We make a request v3.1.0 without a Role " + ApiRole.canSetCallLimits)
|
||||
val Some((c, _)) = user1
|
||||
val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.id.get).getOrElse(0)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").PUT <@(user1)
|
||||
val response310 = makePutRequest(request310, write(callLimitJson1))
|
||||
Then("We should get a 403")
|
||||
org.scalameta.logger.elem(response310.body)
|
||||
response310.code should equal(403)
|
||||
And("error should be " + UserHasMissingRoles + CanSetCallLimit)
|
||||
response310.body.extract[ErrorMessage].error should equal (UserHasMissingRoles + CanSetCallLimit)
|
||||
And("error should be " + UserHasMissingRoles + CanSetCallLimits)
|
||||
response310.body.extract[ErrorMessage].error should equal (UserHasMissingRoles + CanSetCallLimits)
|
||||
}
|
||||
scenario("We will try to set calls limit per minute with a proper Role " + ApiRole.canGetConsumers, ApiEndpoint, VersionOfApi) {
|
||||
When("We make a request v3.1.0 with a Role " + ApiRole.canSetCallLimit)
|
||||
scenario("We will try to set calls limit per minute with a proper Role " + ApiRole.canSetCallLimits, ApiEndpoint, VersionOfApi) {
|
||||
When("We make a request v3.1.0 with a Role " + ApiRole.canSetCallLimits)
|
||||
val Some((c, _)) = user1
|
||||
val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.id.get).getOrElse(0)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanSetCallLimit.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanSetCallLimits.toString)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").PUT <@(user1)
|
||||
val response310 = makePutRequest(request310, write(callLimitJson1))
|
||||
Then("We should get a 200")
|
||||
org.scalameta.logger.elem(response310.body)
|
||||
response310.code should equal(200)
|
||||
response310.body.extract[CallLimitJson]
|
||||
}
|
||||
scenario("We will set calls limit per minute for a Consumer", ApiEndpoint, VersionOfApi) {
|
||||
if(APIUtil.getPropsAsBoolValue("use_consumer_limits", false)) {
|
||||
When("We make a request v3.1.0 with a Role " + ApiRole.canSetCallLimit)
|
||||
When("We make a request v3.1.0 with a Role " + ApiRole.canSetCallLimits)
|
||||
val Some((c, _)) = user1
|
||||
val consumerId: Long = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.id.get).getOrElse(0)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanSetCallLimit.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanSetCallLimits.toString)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").PUT <@(user1)
|
||||
val response01 = makePutRequest(request310, write(callLimitJson2))
|
||||
Then("We should get a 200")
|
||||
@ -104,4 +103,41 @@ class RateLimitTest extends V310ServerSetup {
|
||||
}
|
||||
}
|
||||
|
||||
feature("Rate Limit - " + ApiEndpoint2 + " - " + VersionOfApi)
|
||||
{
|
||||
scenario("We will try to get calls limit per minute for a Consumer - unauthorized access", ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v3.1.0")
|
||||
val Some((c, _)) = user1
|
||||
val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.id.get).getOrElse(0)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").GET
|
||||
val response310 = makeGetRequest(request310)
|
||||
Then("We should get a 400")
|
||||
response310.code should equal(400)
|
||||
And("error should be " + UserNotLoggedIn)
|
||||
response310.body.extract[ErrorMessage].error should equal (UserNotLoggedIn)
|
||||
}
|
||||
scenario("We will try to get calls limit per minute without a proper Role " + ApiRole.canReadCallLimits, ApiEndpoint2, VersionOfApi) {
|
||||
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(_.id.get).getOrElse(0)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").GET <@(user1)
|
||||
val response310 = makeGetRequest(request310)
|
||||
Then("We should get a 403")
|
||||
response310.code should equal(403)
|
||||
And("error should be " + UserHasMissingRoles + CanReadCallLimits)
|
||||
response310.body.extract[ErrorMessage].error should equal (UserHasMissingRoles + CanReadCallLimits)
|
||||
}
|
||||
scenario("We will try to get calls limit per minute with a proper Role " + ApiRole.canReadCallLimits, ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v3.1.0 with a Role " + ApiRole.canReadCallLimits)
|
||||
val Some((c, _)) = user1
|
||||
val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.id.get).getOrElse(0)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanReadCallLimits.toString)
|
||||
val request310 = (v3_1_0_Request / "management" / "consumers" / consumerId / "consumer" / "calls_limit").GET <@(user1)
|
||||
val response310 = makeGetRequest(request310)
|
||||
Then("We should get a 200")
|
||||
response310.code should equal(200)
|
||||
response310.body.extract[CallLimitJson]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user