diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 28d98c3be..0b4acef91 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -351,6 +351,9 @@ object ApiRole { case class CanReadMetrics (requiresBankId: Boolean = false) extends ApiRole lazy val canReadMetrics = CanReadMetrics() + + case class CanGetMetrics (requiresBankId: Boolean = true) extends ApiRole + lazy val canGetMetrics = CanGetMetrics() case class CanGetConfig(requiresBankId: Boolean = false) extends ApiRole lazy val canGetConfig = CanGetConfig() diff --git a/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala b/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala index 2386cd867..d6a36c3d1 100644 --- a/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala +++ b/obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala @@ -21,6 +21,7 @@ import code.api.v5_0_0.JSONFactory500.{createPhysicalCardJson, createViewJsonV50 import code.bankconnectors.Connector import code.consent.{ConsentRequests, Consents} import code.entitlement.Entitlement +import code.metrics.APIMetrics import code.model._ import code.model.dataAccess.BankAccountCreation import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _} @@ -1537,6 +1538,93 @@ trait APIMethods500 { } } + staticResourceDocs += ResourceDoc( + getMetricsAtBank, + implementedInApiVersion, + nameOf(getMetricsAtBank), + "GET", + "/management/metrics/banks/BANK_ID", + "Get Metrics at Bank", + s"""Get the all metrics at the Bank specified by BANK_ID + | + |require CanReadMetrics role + | + |Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics + | + |Should be able to filter on the following metrics fields + | + |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2 + | + |1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString + | + |2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString + | + |3 limit (for pagination: defaults to 50) eg:limit=200 + | + |4 offset (for pagination: zero index, defaults to 0) eg: offset=10 + | + |5 sort_by (defaults to date field) eg: sort_by=date + | possible values: + | "url", + | "date", + | "user_name", + | "app_name", + | "developer_email", + | "implemented_by_partial_function", + | "implemented_in_version", + | "consumer_id", + | "verb" + | + |6 direction (defaults to date desc) eg: direction=desc + | + |eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=10000&offset=0&anon=false&app_name=TeatApp&implemented_in_version=v2.1.0&verb=POST&user_id=c7b6cb47-cb96-4441-8801-35b57456753a&user_name=susan.uk.29@example.com&consumer_id=78 + | + |Other filters: + | + |7 consumer_id (if null ignore) + | + |8 user_id (if null ignore) + | + |9 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.) + | + |10 url (if null ignore), note: can not contain '&'. + | + |11 app_name (if null ignore) + | + |12 implemented_by_partial_function (if null ignore), + | + |13 implemented_in_version (if null ignore) + | + |14 verb (if null ignore) + | + |15 correlation_id (if null ignore) + | + |16 duration (if null ignore) non digit chars will be silently omitted + | + """.stripMargin, + emptyObjectJson, + metricsJson, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + UnknownError + ), + List(apiTagMetric, apiTagApi, apiTagNewStyle), + Some(List(canGetMetrics))) + + lazy val getMetricsAtBank : OBPEndpoint = { + case "management" :: "metrics" :: "banks" :: bankId :: Nil JsonGet _ => { + cc => { + for { + httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) + (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, cc.callContext) + metrics <- Future(APIMetrics.apiMetrics.vend.getAllMetrics(obpQueryParams ::: List(OBPBankId(bankId)))) + } yield { + (JSONFactory210.createMetricsJson(metrics), HttpCode.`200`(callContext)) + } + } + } + } staticResourceDocs += ResourceDoc( getSystemView, diff --git a/obp-api/src/main/scala/code/metrics/MappedMetrics.scala b/obp-api/src/main/scala/code/metrics/MappedMetrics.scala index e644ad523..e1654d828 100644 --- a/obp-api/src/main/scala/code/metrics/MappedMetrics.scala +++ b/obp-api/src/main/scala/code/metrics/MappedMetrics.scala @@ -125,6 +125,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{ .flatMap(consumerIdToPrimaryKey) .map(By(MappedMetric.consumerId, _) ) + val bankId = queryParams.collect { case OBPBankId(value) => Like(MappedMetric.url, s"%banks/$value%") }.headOption val userId = queryParams.collect { case OBPUserId(value) => By(MappedMetric.userId, value) }.headOption val url = queryParams.collect { case OBPUrl(value) => By(MappedMetric.url, value) }.headOption val appName = queryParams.collect { case OBPAppName(value) => By(MappedMetric.appName, value) }.headOption @@ -149,6 +150,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{ ordering, consumerId.toSeq, userId.toSeq, + bankId.toSeq, url.toSeq, appName.toSeq, implementedInVersion.toSeq, diff --git a/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala new file mode 100644 index 000000000..78b389c05 --- /dev/null +++ b/obp-api/src/test/scala/code/api/v5_0_0/MetricsTest.scala @@ -0,0 +1,96 @@ +/** +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. +Osloer Strasse 16/17 +Berlin 13359, Germany + +This product includes software developed at +TESOBE (http://www.tesobe.com/) + + */ +package code.api.v5_0_0 + +import code.api.util.APIUtil.OAuth._ +import code.api.util.ApiRole.CanGetMetrics +import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn} +import code.api.v2_1_0.MetricsJson +import code.api.v5_0_0.APIMethods500.Implementations5_0_0 +import code.entitlement.Entitlement +import code.setup.APIResponse +import com.github.dwickern.macros.NameOf.nameOf +import com.openbankproject.commons.model.ErrorMessage +import com.openbankproject.commons.util.ApiVersion +import org.scalatest.Tag + +class MetricsTest extends V500ServerSetup { + override def beforeAll(): Unit = { + super.beforeAll() + } + + override def afterAll(): Unit = { + super.afterAll() + } + + /** + * Test tags + * Example: To run tests with tag "getPermissions": + * mvn test -D tagsToInclude + * + * This is made possible by the scalatest maven plugin + */ + object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString) + object ApiEndpoint1 extends Tag(nameOf(Implementations5_0_0.getMetricsAtBank)) + + lazy val bankId = testBankId1.value + + def getMetrics(consumerAndToken: Option[(Consumer, Token)], bankId: String): APIResponse = { + val request = v5_0_0_Request / "management" / "metrics" / "banks" / bankId <@(consumerAndToken) + makeGetRequest(request) + } + + feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") { + scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + When(s"We make a request $ApiEndpoint1") + val response400 = getMetrics(None, bankId) + Then("We should get a 401") + response400.code should equal(401) + response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) + } + } + feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") { + scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + When(s"We make a request $ApiEndpoint1") + val response400 = getMetrics(user1, bankId) + Then("We should get a 403") + response400.code should equal(403) + response400.body.extract[ErrorMessage].message contains (UserHasMissingRoles + CanGetMetrics) should be (true) + } + } + feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access with proper Role") { + scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + When(s"We make a request $ApiEndpoint1") + Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanGetMetrics.toString) + val response400 = getMetrics(user1, bankId) + Then("We should get a 200") + response400.code should equal(200) + response400.body.extract[MetricsJson] + } + } + +}