diff --git a/obp-api/pom.xml b/obp-api/pom.xml
index 4bb7318dd..557ae450d 100644
--- a/obp-api/pom.xml
+++ b/obp-api/pom.xml
@@ -360,6 +360,17 @@
client
4.0.1
+
+ io.swagger.parser.v3
+ swagger-parser
+ 2.0.13
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.9.8
+
+
diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template
index 31047a7a8..097d85a5e 100644
--- a/obp-api/src/main/resources/props/sample.props.template
+++ b/obp-api/src/main/resources/props/sample.props.template
@@ -6,7 +6,7 @@
### Base configuration
-## Which data connector to use, if config star as connector, should make sure other connector config appropriate and works
+## Which data connector to use, if config `star` as connector, please also check `starConnector_supported_types`
connector=mapped
#connector=mongodb
#connector=kafka
@@ -17,6 +17,9 @@ connector=mapped
#connector=star
#connector=...
+## if connector = star, then need to set which connectors will be used. For now, obp support rest, akka, kafka. If you set kafka, then you need to start the kafka server.
+#starConnector_supported_types=rest,akka,kafka
+
## whether export LocalMappedConnector methods as endpoints, it is just for develop, default is false
#connector.export.LocalMappedConnector=false
@@ -32,9 +35,9 @@ connector=mapped
#connector.cache.ttl.seconds.getCounterpartiesFromTransaction=10
#connector.cache.ttl.seconds.APIMethods121.getTransactions=10
-## MethodRouting cache time-to-live in seconds, caching defaults to 30 seconds
+## MethodRouting cache time-to-live in seconds
#methodRouting.cache.ttl.seconds=30
-## webui props cache time-to-live in seconds, caching defaults to 20 seconds
+## webui props cache time-to-live in seconds
#webui.props.cache.ttl.seconds=20
## enable logging all the database queries in log file
diff --git a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
index 001e57782..05bea2a6c 100644
--- a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
+++ b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
@@ -220,7 +220,7 @@ class Boot extends MdcLoggable {
// ensure our relational database's tables are created/fit the schema
val connector = APIUtil.getPropsValue("connector").openOrThrowException("no connector set")
- if(connector != "mongodb" || connector == "star")
+ if(connector != "mongodb")
schemifyAll()
// This sets up MongoDB config (for the mongodb connector)
@@ -242,9 +242,11 @@ class Boot extends MdcLoggable {
val actorSystem = ObpActorSystem.startLocalActorSystem()
connector match {
- case ("akka_vDec2018"| "star") =>
+ case "akka_vDec2018" =>
// Start Actor system of Akka connector
ObpActorSystem.startNorthSideAkkaConnectorActorSystem()
+ case "star" if (APIUtil.getPropsValue("starConnector_supported_types","").split(",").contains("akka")) =>
+ ObpActorSystem.startNorthSideAkkaConnectorActorSystem()
case _ => // Do nothing
}
@@ -336,7 +338,7 @@ class Boot extends MdcLoggable {
WebhookHelperActors.startLocalWebhookHelperWorkers(actorSystem)
- if (connector.startsWith("kafka") || connector == "star") {
+ if (connector.startsWith("kafka") || (connector == "star" && APIUtil.getPropsValue("starConnector_supported_types","").split(",").contains("kafka"))) {
logger.info(s"KafkaHelperActors.startLocalKafkaHelperWorkers( ${actorSystem} ) starting")
KafkaHelperActors.startLocalKafkaHelperWorkers(actorSystem)
// Start North Side Consumer if it's not already started
diff --git a/obp-api/src/main/scala/code/api/APIBuilder/APIBuilderModel.scala b/obp-api/src/main/scala/code/api/APIBuilder/APIBuilderModel.scala
index 656dc3827..2d4d6be08 100644
--- a/obp-api/src/main/scala/code/api/APIBuilder/APIBuilderModel.scala
+++ b/obp-api/src/main/scala/code/api/APIBuilder/APIBuilderModel.scala
@@ -257,15 +257,15 @@ object APIBuilderModel
def overwriteApiCode(apiSource: Source, jsonFactorySource:Source =jsonFactorySource) = {
//APIMethods_APIBuilder.scala
- overwriteCurrentFile(apiSource,"src/main/scala/code/api/builder/APIMethods_APIBuilder.scala")
+ overwriteCurrentFile(apiSource,"obp-api/src/main/scala/code/api/builder/APIMethods_APIBuilder.scala")
//JsonFactory_APIBuilder.scala
- overwriteCurrentFile(jsonFactorySource, "src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala")
+ overwriteCurrentFile(jsonFactorySource, "obp-api/src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala")
println("Congratulations! You make the new APIs. Please restart OBP-API server!")
}
- val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("src/main/scala/code/api/APIBuilder/APIModelSource.json")
+ val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("obp-api/src/main/scala/code/api/APIBuilder/APIModelSource.json")
//"/templates"
val apiUrl= getApiUrl(jsonJValueFromFile)
diff --git a/obp-api/src/main/scala/code/api/APIBuilder/apiResourceDoc/APIBuilder.scala b/obp-api/src/main/scala/code/api/APIBuilder/apiResourceDoc/APIBuilder.scala
index d18b005ec..81c1ac0db 100644
--- a/obp-api/src/main/scala/code/api/APIBuilder/apiResourceDoc/APIBuilder.scala
+++ b/obp-api/src/main/scala/code/api/APIBuilder/apiResourceDoc/APIBuilder.scala
@@ -36,7 +36,7 @@ object APIBuilder
{
def main(args: Array[String]): Unit = overwriteApiCode(apiSource,jsonFactorySource)
- val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("src/main/scala/code/api/APIBuilder/apiResourceDoc/apisResource.json")
+ val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("obp-api/src/main/scala/code/api/APIBuilder/apiResourceDoc/apisResource.json")
val resourceDocsJObject= jsonJValueFromFile.\("resource_docs").children.asInstanceOf[List[JObject]]
@@ -210,7 +210,7 @@ object APIBuilder
cc => {
for {
u <- $getMultipleAuthenticationStatement
- jsonStringFromFile = scala.io.Source.fromFile("src/main/scala/code/api/APIBuilder/apisResource.json").mkString
+ jsonStringFromFile = scala.io.Source.fromFile("obp-api/src/main/scala/code/api/APIBuilder/apisResource.json").mkString
jsonJValueFromFile = json.parse(jsonStringFromFile)
resourceDocsJObject= jsonJValueFromFile.\("resource_docs").children.asInstanceOf[List[JObject]]
getMethodJValue = resourceDocsJObject.filter(jObject => jObject.\("request_verb") == JString("GET")&& !jObject.\("request_url").asInstanceOf[JString].values.contains("_ID")).head
@@ -380,7 +380,7 @@ trait APIMethods_APIBuilder
val ImplementationsBuilderAPI = new Object()
{
- val apiVersion: ApiVersion = ApiVersion.apiBuilder
+ val apiVersion = ApiVersion.apiBuilder
val resourceDocs = ArrayBuffer[ResourceDoc]()
val apiRelations = ArrayBuffer[ApiRelation]()
val codeContext = CodeContext(resourceDocs, apiRelations)
diff --git a/obp-api/src/main/scala/code/api/APIBuilder/swagger/APIBuilderSwagger.scala b/obp-api/src/main/scala/code/api/APIBuilder/swagger/APIBuilderSwagger.scala
index 454a5c93a..a8c16cf2d 100644
--- a/obp-api/src/main/scala/code/api/APIBuilder/swagger/APIBuilderSwagger.scala
+++ b/obp-api/src/main/scala/code/api/APIBuilder/swagger/APIBuilderSwagger.scala
@@ -35,7 +35,7 @@ import scala.meta._
object APIBuilderSwagger {
def main(args: Array[String]): Unit = overwriteApiCode(apiSource,jsonFactorySource)
- val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("src/main/scala/code/api/APIBuilder/swagger/swaggerResource.json")
+ val jsonJValueFromFile: JValue = APIUtil.getJValueFromFile("obp-api/src/main/scala/code/api/APIBuilder/swagger/swaggerResource.json")
val getSingleApiResponseBody: JValue = jsonJValueFromFile \\("foo")\"foo"\"value"
//"template"
@@ -328,7 +328,7 @@ trait APIMethods_APIBuilder
val ImplementationsBuilderAPI = new Object()
{
- val apiVersion: ApiVersion = ApiVersion.apiBuilder
+ val apiVersion = ApiVersion.apiBuilder
val resourceDocs = ArrayBuffer[ResourceDoc]()
val apiRelations = ArrayBuffer[ApiRelation]()
val codeContext = CodeContext(resourceDocs, apiRelations)
diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala
index 0c61dc161..cc648fac5 100644
--- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala
+++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala
@@ -5,7 +5,7 @@ import java.util.Date
import code.api.Constant
import code.api.UKOpenBanking.v2_0_0.JSONFactory_UKOpenBanking_200
import code.api.UKOpenBanking.v2_0_0.JSONFactory_UKOpenBanking_200.{Account, AccountBalancesUKV200, AccountInner, AccountList, Accounts, BalanceJsonUKV200, BalanceUKOpenBankingJson, BankTransactionCodeJson, CreditLineJson, DataJsonUKV200, Links, MetaBisJson, MetaInnerJson, TransactionCodeJson, TransactionInnerJson, TransactionsInnerJson, TransactionsJsonUKV200}
-import code.api.berlin.group.v1.JSONFactory_BERLIN_GROUP_1.{AccountBalance, AccountBalances, AmountOfMoneyV1, ClosingBookedBody, ExpectedBody, TransactionJsonV1, TransactionsJsonV1, ViewAccount}
+import code.api.berlin.group.v1.JSONFactory_BERLIN_GROUP_1.{AccountBalanceV1, AccountBalances, AmountOfMoneyV1, Balances, ClosingBookedBody, CoreAccountJsonV1, CoreAccountsJsonV1, ExpectedBody, TransactionJsonV1, Transactions, TransactionsJsonV1, ViewAccount}
import code.api.util.APIUtil.{defaultJValue, _}
import code.api.util.ApiRole._
import code.api.util.{ApiTrigger, ExampleValue}
@@ -15,6 +15,8 @@ import code.api.v3_0_0.JSONFactory300.createBranchJsonV300
import code.api.v3_0_0.custom.JSONFactoryCustom300
import code.api.v3_0_0.{LobbyJsonV330, _}
import code.api.v3_1_0.{BadLoginStatusJson, ContactDetailsJson, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _}
+import code.api.v3_0_0.{EmptyElasticSearch, LobbyJsonV330, NewModeratedCoreAccountJsonV300, _}
+import code.api.v3_1_0.{AccountBalanceV310, AccountsBalancesV310Json, BadLoginStatusJson, ContactDetailsJson, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _}
import code.branches.Branches.{Branch, DriveUpString, LobbyString}
import code.sandbox.SandboxData
import code.transactionrequests.TransactionRequests.TransactionRequestTypes._
@@ -25,6 +27,8 @@ import com.openbankproject.commons.model
import com.openbankproject.commons.model.PinResetReason.{FORGOT, GOOD_SECURITY_PRACTICE}
import com.openbankproject.commons.model.{ViewBasic, _}
import com.openbankproject.commons.util.ReflectUtils
+import com.openbankproject.commons.model.{AccountBalance, GeoTag, ViewBasic, _}
+import net.liftweb.json
import scala.collection.immutable.List
@@ -2651,13 +2655,13 @@ object SwaggerDefinitionsJSON {
lastActionDateTime = DateWithDayExampleObject
)
- val accountBalance = AccountBalance(
+ val accountBalanceV1 = AccountBalanceV1(
closingBooked = closingBookedBody,
expected = expectedBody
)
val accountBalances = AccountBalances(
- `balances` = List(accountBalance)
+ `balances` = List(accountBalanceV1)
)
val transactionJsonV1 = TransactionJsonV1(
@@ -3414,7 +3418,21 @@ object SwaggerDefinitionsJSON {
val elasticSearchQuery = ElasticSearchQuery(emptyElasticSearch)
val elasticSearchJsonV300 = ElasticSearchJsonV300(elasticSearchQuery)
+
+ val accountBalanceV310 = AccountBalanceV310(
+ id = accountIdExample.value,
+ label = labelExample.value,
+ bank_id = bankIdExample.value,
+ account_routings = List(accountRouting),
+ balance = amountOfMoney
+ )
+ val accountBalancesV310Json = AccountsBalancesV310Json(
+ accounts = List(accountBalanceV310),
+ overall_balance = amountOfMoney,
+ overall_balance_date = DateWithMsExampleObject
+ )
+
//The common error or success format.
//Just some helper format to use in Json
case class NoSupportYet()
diff --git a/obp-api/src/main/scala/code/api/STET/v1_4/AISPApi.scala b/obp-api/src/main/scala/code/api/STET/v1_4/AISPApi.scala
index 9b6cc38c7..1f4f20aab 100644
--- a/obp-api/src/main/scala/code/api/STET/v1_4/AISPApi.scala
+++ b/obp-api/src/main/scala/code/api/STET/v1_4/AISPApi.scala
@@ -209,8 +209,8 @@ The TPP sends a request to the ASPSP for retrieving the list of the PSU payment
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u, bankId)
-
- Full(accounts) <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts,callContext)}
+
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
(createTransactionListJSON(accounts), callContext)
diff --git a/obp-api/src/main/scala/code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala b/obp-api/src/main/scala/code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala
index d9fa4dc9b..46ae49a49 100644
--- a/obp-api/src/main/scala/code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala
+++ b/obp-api/src/main/scala/code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala
@@ -57,9 +57,9 @@ object APIMethods_UKOpenBanking_200 extends RestHelper{
for {
(Full(u), callContext) <- authorizedAccess(cc)
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_200.createAccountsListJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_200.createAccountsListJSON(accounts), callContext)
}
}
}
@@ -144,9 +144,9 @@ object APIMethods_UKOpenBanking_200 extends RestHelper{
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u) map {
_.filter(_.accountId.value == accountId.value)
}
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_200.createAccountJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_200.createAccountJSON(accounts), callContext)
}
}
}
@@ -229,10 +229,10 @@ object APIMethods_UKOpenBanking_200 extends RestHelper{
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_200.createBalancesJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_200.createBalancesJSON(accounts), callContext)
}
}
}
diff --git a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/AccountsApi.scala b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/AccountsApi.scala
index 36bbbcf56..288524b79 100644
--- a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/AccountsApi.scala
+++ b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/AccountsApi.scala
@@ -2,7 +2,7 @@ package code.api.UKOpenBanking.v3_1_0
import code.api.berlin.group.v1_3.JvalueCaseClass
import code.api.util.APIUtil._
-import code.api.util.ApiTag
+import code.api.util.{ApiTag, NewStyle}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.bankconnectors.Connector
@@ -110,9 +110,9 @@ object APIMethods_AccountsApi extends RestHelper {
for {
(Full(u), callContext) <- authorizedAccess(cc)
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_310.createAccountsListJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_310.createAccountsListJSON(accounts), callContext)
}
}
@@ -202,9 +202,9 @@ object APIMethods_AccountsApi extends RestHelper {
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u) map {
_.filter(_.accountId.value == accountId.value)
}
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_310.createAccountJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_310.createAccountJSON(accounts), callContext)
}
}
}
diff --git a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/BalancesApi.scala b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/BalancesApi.scala
index 572fd3fa6..228489d65 100644
--- a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/BalancesApi.scala
+++ b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/BalancesApi.scala
@@ -222,10 +222,10 @@ object APIMethods_BalancesApi extends RestHelper {
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
- accounts <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_UKOpenBanking_310.createBalancesJSON(accounts.getOrElse(Nil)), callContext)
+ (JSONFactory_UKOpenBanking_310.createBalancesJSON(accounts), callContext)
}
}
}
diff --git a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/TransactionsApi.scala b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/TransactionsApi.scala
index 8e16d5212..186286446 100644
--- a/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/TransactionsApi.scala
+++ b/obp-api/src/main/scala/code/api/UKOpenBanking/v3_1_0/TransactionsApi.scala
@@ -1022,7 +1022,7 @@ object APIMethods_TransactionsApi extends RestHelper {
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
- Full(accounts) <- Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
transactionAndTransactionRequestTuple = for{
bankAccount <- accounts
diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1/JSONFactory_BERLIN_GROUP_1.scala b/obp-api/src/main/scala/code/api/berlin/group/v1/JSONFactory_BERLIN_GROUP_1.scala
index 6dd68cbf0..bf66cecd2 100644
--- a/obp-api/src/main/scala/code/api/berlin/group/v1/JSONFactory_BERLIN_GROUP_1.scala
+++ b/obp-api/src/main/scala/code/api/berlin/group/v1/JSONFactory_BERLIN_GROUP_1.scala
@@ -44,11 +44,11 @@ object JSONFactory_BERLIN_GROUP_1 extends CustomJsonFormats {
amount : AmountOfMoneyV1,
lastActionDateTime: Date
)
- case class AccountBalance(
+ case class AccountBalanceV1(
closingBooked: ClosingBookedBody,
expected: ExpectedBody
)
- case class AccountBalances(`balances`: List[AccountBalance])
+ case class AccountBalances(`balances`: List[AccountBalanceV1])
case class TransactionsJsonV1(
transactions_booked: List[TransactionJsonV1],
@@ -93,7 +93,7 @@ object JSONFactory_BERLIN_GROUP_1 extends CustomJsonFormats {
val sumOfAll = (BigDecimal(moderatedAccount.balance) + sumOfAllUncompletedTransactionrequests).toString()
AccountBalances(
- AccountBalance(
+ AccountBalanceV1(
closingBooked = ClosingBookedBody(
amount = AmountOfMoneyV1(currency = moderatedAccount.currency.getOrElse(""), content = moderatedAccount.balance),
date = APIUtil.DateWithDayFormat.format(latestCompletedEndDate)
diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala
index 661bf6556..a0fddfa76 100644
--- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala
+++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala
@@ -270,10 +270,10 @@ of the PSU at this ASPSP.
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u, bankId)
- Full((coreAccounts)) <- {Connector.connector.vend.getBankAccounts(availablePrivateAccounts, callContext)}
+ (accounts, callContext)<- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
} yield {
- (JSONFactory_BERLIN_GROUP_1_3.createAccountListJson(coreAccounts, u), callContext)
+ (JSONFactory_BERLIN_GROUP_1_3.createAccountListJson(accounts, u), callContext)
}
}
}
diff --git a/obp-api/src/main/scala/code/api/builder/APIMethods_APIBuilder.scala b/obp-api/src/main/scala/code/api/builder/APIMethods_APIBuilder.scala
index d5cf37312..635dbb469 100644
--- a/obp-api/src/main/scala/code/api/builder/APIMethods_APIBuilder.scala
+++ b/obp-api/src/main/scala/code/api/builder/APIMethods_APIBuilder.scala
@@ -1,10 +1,9 @@
package code.api.builder
import java.util.UUID
-
import code.api.builder.JsonFactory_APIBuilder._
import code.api.util.APIUtil._
import code.api.util.ApiTag._
-import code.api.util.{ApiVersion, CustomJsonFormats}
+import code.api.util.ApiVersion
import code.api.util.ErrorMessages._
import net.liftweb.common.Full
import net.liftweb.http.rest.RestHelper
@@ -13,7 +12,6 @@ import net.liftweb.json.Extraction._
import net.liftweb.json._
import net.liftweb.mapper.By
import net.liftweb.util.Helpers.tryo
-
import scala.collection.immutable.Nil
import scala.collection.mutable.ArrayBuffer
trait APIMethods_APIBuilder { self: RestHelper =>
@@ -22,10 +20,10 @@ trait APIMethods_APIBuilder { self: RestHelper =>
val resourceDocs = ArrayBuffer[ResourceDoc]()
val apiRelations = ArrayBuffer[ApiRelation]()
val codeContext = CodeContext(resourceDocs, apiRelations)
- implicit val formats = CustomJsonFormats.formats
- val TemplateNotFound = "OBP-31001: Template not found. Please specify a valid value for TEMPLATE_ID."
- def endpointsOfBuilderAPI = getTemplates :: getTemplate :: createTemplate :: deleteTemplate :: Nil
- resourceDocs += ResourceDoc(getTemplates, apiVersion, "getTemplates", "GET", "/templates", "Get Templates", "Return All Templates", emptyObjectJson, templatesJson, List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
+ implicit val formats = code.api.util.CustomJsonFormats.formats
+ val TemplatesNotFound = "OBP-31001: Templates not found. Please specify a valid value for TEMPLATES_ID."
+ def endpointsOfBuilderAPI = getTemplates :: createTemplate :: getTemplate :: deleteTemplate :: Nil
+ resourceDocs += ResourceDoc(getTemplates, apiVersion, "getTemplates", "GET", "/templates", "Get Templates", "Return All my templates. Authentication is Mandatory.", emptyObjectJson, templatesJson, List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
lazy val getTemplates: OBPEndpoint = {
case ("templates" :: Nil) JsonGet req =>
cc => {
@@ -34,16 +32,7 @@ trait APIMethods_APIBuilder { self: RestHelper =>
}
}
}
- resourceDocs += ResourceDoc(getTemplate, apiVersion, "getTemplate", "GET", "/templates/TEMPLATE_ID", "Get Template", "Return One Template By Id", emptyObjectJson, templateJson, List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
- lazy val getTemplate: OBPEndpoint = {
- case ("templates" :: templateId :: Nil) JsonGet _ =>
- cc => {
- for (u <- cc.user ?~ UserNotLoggedIn; template <- APIBuilder_Connector.getTemplateById(templateId) ?~! TemplateNotFound; templateJson = JsonFactory_APIBuilder.createTemplate(template); jsonObject: JValue = decompose(templateJson)) yield {
- successJsonResponse(jsonObject)
- }
- }
- }
- resourceDocs += ResourceDoc(createTemplate, apiVersion, "createTemplate", "POST", "/templates", "Create Template", "Create One Template", createTemplateJson, templateJson, List(UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
+ resourceDocs += ResourceDoc(createTemplate, apiVersion, "createTemplate", "POST", "/templates", "Create Template", "Create template. Authentication is Mandatory.", createTemplateJson, templateJson, List(UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
lazy val createTemplate: OBPEndpoint = {
case ("templates" :: Nil) JsonPost json -> _ =>
cc => {
@@ -52,15 +41,20 @@ trait APIMethods_APIBuilder { self: RestHelper =>
}
}
}
- resourceDocs += ResourceDoc(deleteTemplate, apiVersion, "deleteTemplate", "DELETE", "/templates/TEMPLATE_ID", "Delete Template", "Delete One Template", emptyObjectJson, emptyObjectJson.copy("true"), List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
+ resourceDocs += ResourceDoc(getTemplate, apiVersion, "getTemplate", "GET", "/templates/{template_id}", "Get Template", "Return one template. Authentication is Mandatory.", emptyObjectJson, templateJson, List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
+ lazy val getTemplate: OBPEndpoint = {
+ case ("templates" :: templateId :: Nil) JsonGet _ =>
+ cc => {
+ for (u <- cc.user ?~ UserNotLoggedIn; template <- APIBuilder_Connector.getTemplateById(templateId) ?~! TemplatesNotFound; templateJson = JsonFactory_APIBuilder.createTemplate(template); jsonObject: JValue = decompose(templateJson)) yield {
+ successJsonResponse(jsonObject)
+ }
+ }
+ }
+ resourceDocs += ResourceDoc(deleteTemplate, apiVersion, "deleteTemplate", "DELETE", "/templates/{template_id}", "Delete Template", "Delete template. Authentication is Mandatory.", emptyObjectJson, emptyObjectJson.copy("true"), List(UserNotLoggedIn, UnknownError), Catalogs(notCore, notPSD2, notOBWG), apiTagApiBuilder :: Nil)
lazy val deleteTemplate: OBPEndpoint = {
case ("templates" :: templateId :: Nil) JsonDelete _ =>
cc => {
- for (
- u <- cc.user ?~ UserNotLoggedIn;
- template <- APIBuilder_Connector.getTemplateById(templateId) ?~! TemplateNotFound;
- deleted <- APIBuilder_Connector.deleteTemplate(templateId)
- ) yield {
+ for (u <- cc.user ?~ UserNotLoggedIn; template <- APIBuilder_Connector.getTemplateById(templateId) ?~! TemplatesNotFound; deleted <- APIBuilder_Connector.deleteTemplate(templateId)) yield {
if (deleted) noContentJsonResponse else errorJsonResponse("Delete not completed")
}
}
@@ -68,25 +62,25 @@ trait APIMethods_APIBuilder { self: RestHelper =>
}
}
object APIBuilder_Connector {
- val allAPIBuilderModels = List(MappedTemplate_4824100653501473508)
- def createTemplate(createTemplateJson: CreateTemplateJson) = Full(MappedTemplate_4824100653501473508.create.mTemplateId(generateUUID()).mAuthor(createTemplateJson.author).mPages(createTemplateJson.pages).mPoints(createTemplateJson.points).saveMe())
- def getTemplates() = Full(MappedTemplate_4824100653501473508.findAll())
- def getTemplateById(templateId: String) = MappedTemplate_4824100653501473508.find(By(MappedTemplate_4824100653501473508.mTemplateId, templateId))
- def deleteTemplate(templateId: String) = MappedTemplate_4824100653501473508.find(By(MappedTemplate_4824100653501473508.mTemplateId, templateId)).map(_.delete_!)
+ val allAPIBuilderModels = List(MappedTemplates_430794570390706560)
+ def createTemplate(createTemplateJson: CreateTemplateJson) = Full(MappedTemplates_430794570390706560.create.mTemplateId(UUID.randomUUID().toString).mAuthor(createTemplateJson.author).mPages(createTemplateJson.pages).mPoints(createTemplateJson.points).saveMe())
+ def getTemplates() = Full(MappedTemplates_430794570390706560.findAll())
+ def getTemplateById(templateId: String) = MappedTemplates_430794570390706560.find(By(MappedTemplates_430794570390706560.mTemplateId, templateId))
+ def deleteTemplate(templateId: String) = MappedTemplates_430794570390706560.find(By(MappedTemplates_430794570390706560.mTemplateId, templateId)).map(_.delete_!)
}
import net.liftweb.mapper._
-class MappedTemplate_4824100653501473508 extends Template with LongKeyedMapper[MappedTemplate_4824100653501473508] with IdPK {
+class MappedTemplates_430794570390706560 extends Template with LongKeyedMapper[MappedTemplates_430794570390706560] with IdPK {
object mAuthor extends MappedString(this, 100)
override def author: String = mAuthor.get
object mPages extends MappedInt(this)
override def pages: Int = mPages.get
object mPoints extends MappedDouble(this)
override def points: Double = mPoints.get
- def getSingleton = MappedTemplate_4824100653501473508
+ def getSingleton = MappedTemplates_430794570390706560
object mTemplateId extends MappedString(this, 100)
override def templateId: String = mTemplateId.get
}
-object MappedTemplate_4824100653501473508 extends MappedTemplate_4824100653501473508 with LongKeyedMetaMapper[MappedTemplate_4824100653501473508]
+object MappedTemplates_430794570390706560 extends MappedTemplates_430794570390706560 with LongKeyedMetaMapper[MappedTemplates_430794570390706560]
trait Template { `_` =>
def author: String
def pages: Int
diff --git a/obp-api/src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala b/obp-api/src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala
index f854cd1cf..abd4a78be 100644
--- a/obp-api/src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala
+++ b/obp-api/src/main/scala/code/api/builder/JsonFactory_APIBuilder.scala
@@ -1,7 +1,7 @@
package code.api.builder
import code.api.util.APIUtil
+case class TemplateJson(id: String = """11231231312""", author: String = """Chinua Achebe""", pages: Int = 209, points: Double = 1.3)
case class CreateTemplateJson(author: String = """Chinua Achebe""", pages: Int = 209, points: Double = 1.3)
-case class TemplateJson(template_id: String = """11231231312""", author: String = """Chinua Achebe""", pages: Int = 209, points: Double = 1.3)
object JsonFactory_APIBuilder {
val templateJson = TemplateJson()
val templatesJson = List(templateJson)
diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala
index ba9dff744..58e8e1ab2 100644
--- a/obp-api/src/main/scala/code/api/util/APIUtil.scala
+++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala
@@ -2496,6 +2496,18 @@ Returns a string showed to the developer
def createBasicUserAuthContextJson(userAuthContexts : List[UserAuthContext]) : List[BasicUserAuthContext] = {
userAuthContexts.map(createBasicUserAuthContext)
}
+
+ def createBasicUserAuthContextJsonFromCallContext(callContext : CallContext) : List[BasicGeneralContext] = {
+ val requestHeaders: List[HTTPParam] = callContext.requestHeaders
+
+ //Only these Pass-Through headers can be propagated to Adapter side.
+ val passThroughHeaders: List[HTTPParam] = requestHeaders
+ .filter(requestHeader => requestHeader.name.startsWith("Pass-Through"))
+
+ passThroughHeaders.map(header => BasicGeneralContext(
+ key = header.name,
+ value = if (header.values.isEmpty) "" else header.values.head))
+ }
def createAuthInfoCustomerJson(customer : Customer) : InternalBasicCustomer = {
InternalBasicCustomer(
diff --git a/obp-api/src/main/scala/code/api/util/ApiSession.scala b/obp-api/src/main/scala/code/api/util/ApiSession.scala
index 5bf704896..a3fb4262b 100644
--- a/obp-api/src/main/scala/code/api/util/ApiSession.scala
+++ b/obp-api/src/main/scala/code/api/util/ApiSession.scala
@@ -57,8 +57,10 @@ case class CallContext(
views <- tryo(permission.views)
linkedCustomers <- tryo(CustomerX.customerProvider.vend.getCustomersByUserId(user.userId))
likedCustomersBasic = if (linkedCustomers.isEmpty) None else Some(createInternalLinkedBasicCustomersJson(linkedCustomers))
- userAuthContexts<- UserAuthContextProvider.userAuthContextProvider.vend.getUserAuthContextsBox(user.userId)
- basicUserAuthContexts = if (userAuthContexts.isEmpty) None else Some(createBasicUserAuthContextJson(userAuthContexts))
+ userAuthContexts<- UserAuthContextProvider.userAuthContextProvider.vend.getUserAuthContextsBox(user.userId)
+ basicUserAuthContextsFromDatabase = if (userAuthContexts.isEmpty) None else Some(createBasicUserAuthContextJson(userAuthContexts))
+ generalContextFromPassThroughHeaders = createBasicUserAuthContextJsonFromCallContext(this)
+ basicUserAuthContexts = Some(basicUserAuthContextsFromDatabase.getOrElse(List.empty[BasicUserAuthContext]))
authViews<- tryo(
for{
view <- views
@@ -79,7 +81,7 @@ case class CallContext(
correlationId = this.correlationId,
sessionId = this.sessionId,
consumerId = Some(consumerId),
- generalContext = None,
+ generalContext = Some(generalContextFromPassThroughHeaders),
outboundAdapterAuthInfo = Some(OutboundAdapterAuthInfo(
userId = currentResourceUserId,
username = username,
diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala
index 97585c4a2..6793ac894 100644
--- a/obp-api/src/main/scala/code/api/util/NewStyle.scala
+++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala
@@ -204,6 +204,7 @@ object NewStyle {
(nameOf(Implementations3_1_0.createAccount), ApiVersion.v3_1_0.toString),
(nameOf(Implementations3_1_0.saveHistoricalTransaction), ApiVersion.v3_1_0.toString),
(nameOf(Implementations3_1_0.getPrivateAccountByIdFull), ApiVersion.v3_1_0.toString),
+ (nameOf(Implementations3_1_0.getBankAccountsBalances), ApiVersion.v3_1_0.toString),
(nameOf(Implementations4_0_0.getBanks), ApiVersion.v4_0_0.toString)
)
@@ -286,12 +287,27 @@ object NewStyle {
connectorEmptyResponse(_, callContext)
}
}
-
+ def getBalances(callContext: Option[CallContext]) : OBPReturnType[List[Bank]] = {
+ Connector.connector.vend.getBanks(callContext: Option[CallContext]) map {
+ connectorEmptyResponse(_, callContext)
+ }
+ }
def getBankAccount(bankId : BankId, accountId : AccountId, callContext: Option[CallContext]): OBPReturnType[BankAccount] = {
Connector.connector.vend.getBankAccount(bankId, accountId, callContext) map { i =>
(unboxFullOrFail(i._1, callContext,s"$BankAccountNotFound Current BankId is $bankId and Current AccountId is $accountId", 400 ), i._2)
}
}
+ def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): OBPReturnType[List[BankAccount]] = {
+ Connector.connector.vend.getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) map { i =>
+ (unboxFullOrFail(i._1, callContext,s"$InvalidConnectorResponseForGetBankAccounts", 400 ), i._2)
+ }
+ }
+
+ def getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): OBPReturnType[AccountsBalances] = {
+ Connector.connector.vend.getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) map { i =>
+ (unboxFullOrFail(i._1, callContext,s"$InvalidConnectorResponseForGetBankAccounts", 400 ), i._2)
+ }
+ }
def getBankAccountByIban(iban : String, callContext: Option[CallContext]) : OBPReturnType[BankAccount] = {
Connector.connector.vend.getBankAccountByIban(iban : String, callContext: Option[CallContext]) map { i =>
@@ -1507,7 +1523,7 @@ object NewStyle {
}
}
- private[this] val methodRoutingTTL = APIUtil.getPropsValue(s"methodRouting.cache.ttl.seconds", "30").toInt // default 30 seconds
+ private[this] val methodRoutingTTL = APIUtil.getPropsValue(s"methodRouting.cache.ttl.seconds", "0").toInt
def getMethodRoutings(methodName: Option[String], isBankIdExactMatch: Option[Boolean] = None, bankIdPattern: Option[String] = None): List[MethodRoutingT] = {
import scala.concurrent.duration._
diff --git a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
index a1612e42d..e833caeb0 100644
--- a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
+++ b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
@@ -1,11 +1,9 @@
package code.api.v3_1_0
import java.text.SimpleDateFormat
-import java.util.{Date, UUID}
+import java.util.UUID
import java.util.regex.Pattern
-import code.accountholders.AccountHolders
-import code.api.{APIFailureNewStyle, ChargePolicy}
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.ResourceDocs1_4_0.{MessageDocsSwaggerDefinitions, SwaggerDefinitionsJSON, SwaggerJSONFactory}
import code.api.util.APIUtil._
@@ -16,16 +14,13 @@ import code.api.util.ExampleValue._
import code.api.util.NewStyle.HttpCode
import code.api.util._
import code.api.v1_2_1.{JSONFactory, RateLimiting}
-import code.api.v1_3_0.{JSONFactory1_3_0, PostPhysicalCardJSON}
-import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140
import code.api.v2_0_0.CreateMeetingJson
import code.api.v2_1_0._
import code.api.v2_2_0.{CreateAccountJSONV220, JSONFactory220}
import code.api.v3_0_0.JSONFactory300
-import code.api.v3_0_0.JSONFactory300.{createAdapterInfoJson, createCoreBankAccountJSON}
+import code.api.v3_0_0.JSONFactory300.{createAdapterInfoJson}
import code.api.v3_1_0.JSONFactory310._
import code.bankconnectors.Connector
-import code.bankconnectors.akka.AkkaConnector_vDec2018
import code.bankconnectors.rest.RestConnector_vMar2019
import code.consent.{ConsentStatus, Consents}
import code.consumer.Consumers
@@ -33,31 +28,29 @@ import code.context.{UserAuthContextUpdateProvider, UserAuthContextUpdateStatus}
import code.entitlement.Entitlement
import code.kafka.KafkaHelper
import code.loginattempts.LoginAttempt
-import code.methodrouting.MethodRoutingCommons
+import code.methodrouting.{MethodRoutingCommons, MethodRoutingParam}
import code.metrics.APIMetrics
import code.model._
import code.model.dataAccess.{AuthUser, BankAccountCreation}
-import code.transactionrequests.TransactionRequests.TransactionRequestTypes
-import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{COUNTERPARTY, FREE_FORM, SANDBOX_TAN, SEPA}
import com.openbankproject.commons.model.Product
import code.users.Users
import code.util.Helper
import code.views.Views
import code.webhook.AccountWebhook
-import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons, WebUiPropsProvider}
+import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons}
import com.github.dwickern.macros.NameOf.nameOf
import com.nexmo.client.NexmoClient
import com.nexmo.client.sms.messages.TextMessage
import com.openbankproject.commons.model.{CreditLimit, _}
-import net.liftweb.common.{Box, Empty, Failure, Full}
+import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.http.provider.HTTPParam
import net.liftweb.http.rest.RestHelper
-import net.liftweb.json.Serialization.write
+
import net.liftweb.json._
import net.liftweb.util.Helpers.tryo
import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To}
-import net.liftweb.util.{Helpers, Mailer, Props}
-import org.apache.commons.lang3.Validate
+import net.liftweb.util.{Helpers, Mailer}
+import org.apache.commons.lang3.{StringUtils, Validate}
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
@@ -3930,7 +3923,7 @@ trait APIMethods310 {
emptyObjectJson,
ListResult(
"method_routings",
- (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), Some("method-routing-id"))))
+ (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), Some("method-routing-id"))))
)
,
List(
@@ -3976,12 +3969,17 @@ trait APIMethods310 {
|* connector_name is required String value
|* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false
|* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex
+ |* parameters is optional array of key value pairs. You can set some paremeters for this method
|
- |note: if bank_id_pattern is regex, special characters need to do escape, for example:
- |bank_id_pattern = "some\\-id_pattern_\\d+"
+ |note:
+ |
+ |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+"
|""",
- MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*")),
- MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), Some("this-method-routing-Id")),
+ MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx")))),
+ MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"),
+ Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))),
+ Some("this-method-routing-Id")
+ ),
List(
UserNotLoggedIn,
UserHasMissingRoles,
@@ -4036,13 +4034,13 @@ trait APIMethods310 {
|* connector_name is required String value
|* is_bank_id_exact_match is required boolean value, if bank_id_pattern is exact bank_id value, this value is true; if bank_id_pattern is null or a regex, this value is false
|* bank_id_pattern is optional String value, it can be null, a exact bank_id or a regex
+ |* parameters is optional array of key value pairs. You can set some paremeters for this method
+ |note:
|
- |note: if bank_id_pattern is regex, special characters need to do escape, for example:
- |bank_id_pattern = "some\\-id_pattern_\\d+"
- |
+ |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+"
|""",
- MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), None),
- MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), None),
+ MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx")))),
+ MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"),Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), Some("this-method-routing-Id")),
List(
UserNotLoggedIn,
UserHasMissingRoles,
@@ -4061,21 +4059,21 @@ trait APIMethods310 {
_ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateMethodRouting, callContext)
failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[MethodRoutingCommons]} "
- postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
+ putData <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.extract[MethodRoutingCommons].copy(methodRoutingId = Some(methodRoutingId))
}
(_, _) <- NewStyle.function.getMethodRoutingById(methodRoutingId, callContext)
- invalidRegexMsg = s"$InvalidBankIdRegex The bankIdPattern is invalid regex, bankIdPatten: ${postedData.bankIdPattern.orNull} "
+ invalidRegexMsg = s"$InvalidBankIdRegex The bankIdPattern is invalid regex, bankIdPatten: ${putData.bankIdPattern.orNull} "
_ <- NewStyle.function.tryons(invalidRegexMsg, 400, callContext) {
// if do fuzzy match and bankIdPattern not empty, do check the regex is valid
- if(!postedData.isBankIdExactMatch && postedData.bankIdPattern.isDefined) {
- Pattern.compile(postedData.bankIdPattern.get)
+ if(!putData.isBankIdExactMatch && putData.bankIdPattern.isDefined) {
+ Pattern.compile(putData.bankIdPattern.get)
}
}
- Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(postedData)
+ Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(putData)
} yield {
val commonsData: MethodRoutingCommons = methodRouting
(commonsData, HttpCode.`200`(callContext))
@@ -5450,6 +5448,35 @@ trait APIMethods310 {
}
}
+ resourceDocs += ResourceDoc(
+ getBankAccountsBalances,
+ implementedInApiVersion,
+ nameOf(getBankAccountsBalances),
+ "GET",
+ "/banks/BANK_ID/balances",
+ "Get Accounts Balances",
+ """Get the Balances for the Accounts of the current User at one bank.""",
+ emptyObjectJson,
+ accountBalancesV310Json,
+ List(UnknownError),
+ Catalogs(Core, PSD2, OBWG),
+ apiTagAccount :: apiTagPSD2AIS :: apiTagNewStyle :: Nil
+ )
+
+ lazy val getBankAccountsBalances : OBPEndpoint = {
+ case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => {
+ cc =>
+ for {
+ (Full(u), callContext) <- authorizedAccess(cc)
+ (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
+ availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u, bankId)
+ (accountsBalances, callContext)<- NewStyle.function.getBankAccountsBalances(availablePrivateAccounts, callContext)
+ } yield{
+ (createBalancesJson(accountsBalances), HttpCode.`200`(callContext))
+ }
+ }
+ }
+
}
}
diff --git a/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala b/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala
index 3debef2d8..246ba9c79 100644
--- a/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala
+++ b/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala
@@ -34,7 +34,7 @@ import code.api.util.APIUtil.{stringOptionOrNull, stringOrNull}
import code.api.util.RateLimitPeriod.LimitCallPeriod
import code.api.util.{APIUtil, RateLimitPeriod}
import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON}
-import code.api.v1_2_1.{RateLimiting, UserJSONV121, ViewJSONV121}
+import code.api.v1_2_1.{BankJSON, RateLimiting, UserJSONV121, ViewJSONV121}
import code.api.v1_3_0.JSONFactory1_3_0._
import code.api.v1_3_0.{PinResetJSON, ReplacementJSON}
import code.api.v1_4_0.JSONFactory1_4_0.{CustomerFaceImageJson, MetaJsonV140, TransactionRequestAccountJsonV140}
@@ -42,7 +42,7 @@ import code.api.v2_0_0.{MeetingKeysJson, MeetingPresentJson}
import code.api.v2_1_0.JSONFactory210.createLicenseJson
import code.api.v2_1_0.{CustomerCreditRatingJSON, ResourceUserJSON}
import code.api.v2_2_0._
-import code.api.v3_0_0.AccountRuleJsonV300
+import code.api.v3_0_0.{AccountRuleJsonV300, ViewBasicV300}
import code.api.v3_0_0.JSONFactory300.{createAccountRoutingsJSON, createAccountRulesJSON}
import code.consent.MappedConsent
import code.context.UserAuthContextUpdate
@@ -701,6 +701,24 @@ case class PostHistoricalTransactionResponseJson(
charge_policy: String
)
+case class AccountsBalancesV310Json(
+ accounts:List[AccountBalanceV310],
+ overall_balance: AmountOfMoney,
+ overall_balance_date: Date
+)
+case class AccountBalanceV310(
+ id: String,
+ label: String,
+ bank_id: String,
+ account_routings: List[AccountRouting],
+ balance: AmountOfMoney
+)
+
+case class AccountBalancesJson(
+ accounts: List[AccountBalanceV310],
+ overall_balance: AmountOfMoney,
+ overall_balance_date: Date
+)
object JSONFactory310{
def createCheckbookOrdersJson(checkbookOrders: CheckbookOrdersJson): CheckbookOrdersJson =
@@ -1309,5 +1327,19 @@ object JSONFactory310{
)
}
+ def createBalancesJson(accountsBalances: AccountsBalances) = {
+ AccountsBalancesV310Json(
+ accounts = accountsBalances.accounts.map(account => AccountBalanceV310(
+ account.id,
+ account.label,
+ account.bankId,
+ account.accountRoutings,
+ account.balance)
+ ),
+ overall_balance = accountsBalances.overallBalance,
+ overall_balance_date = accountsBalances.overallBalanceDate
+ )
+ }
+
}
diff --git a/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala b/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala
index c8c2ea7ab..03f3bcbe8 100644
--- a/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala
+++ b/obp-api/src/main/scala/code/api/v3_1_0/OBPAPI3_1_0.scala
@@ -376,6 +376,7 @@ object OBPAPI3_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations3_1_0.getWebUiProps ::
Implementations3_1_0.createWebUiProps ::
Implementations3_1_0.deleteWebUiProps ::
+ Implementations3_1_0.getBankAccountsBalances ::
Nil
val allResourceDocs = Implementations3_1_0.resourceDocs ++
diff --git a/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala b/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala
index 2c3278e3e..6027aeb7c 100644
--- a/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala
+++ b/obp-api/src/main/scala/code/api/v4_0_0/OBPAPI4_0_0.scala
@@ -377,6 +377,7 @@ object OBPAPI4_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations3_1_0.getWebUiProps ::
Implementations3_1_0.createWebUiProps ::
Implementations3_1_0.deleteWebUiProps ::
+ Implementations3_1_0.getBankAccountsBalances ::
Nil
diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala
index eb77ce320..835d34df5 100644
--- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala
@@ -273,7 +273,9 @@ trait Connector extends MdcLoggable with CustomJsonFormats{
def getBankAccountByIban(iban : String, callContext: Option[CallContext]) : OBPReturnType[Box[BankAccount]]= Future{(Failure(setUnimplementedError),callContext)}
def getBankAccountByRouting(scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
- def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : Future[Box[List[BankAccount]]]= Future{Failure(setUnimplementedError)}
+ def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : OBPReturnType[Box[List[BankAccount]]]= Future{(Failure(setUnimplementedError), callContext)}
+
+ def getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : OBPReturnType[Box[AccountsBalances]]= Future{(Failure(setUnimplementedError), callContext)}
def getCoreBankAccountsLegacy(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : Box[(List[CoreAccount], Option[CallContext])] =
Failure(setUnimplementedError)
diff --git a/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala b/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala
index d3104fff4..502497b01 100644
--- a/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala
@@ -5,7 +5,7 @@ import code.api.util.APIUtil.{OBPEndpoint, _}
import code.api.util.NewStyle.HttpCode
import code.api.util.{APIUtil, CallContext, OBPQueryParam}
import code.api.v3_1_0.OBPAPI3_1_0.oauthServe
-import com.openbankproject.commons.model.{AccountId, BankId, BankIdAccountId, InboundAdapterCallContext}
+import com.openbankproject.commons.model._
import com.openbankproject.commons.util.ReflectUtils
import com.openbankproject.commons.util.ReflectUtils.{getType, toValueObject}
import net.liftweb.common.{Box, Empty, Failure, Full}
@@ -55,7 +55,7 @@ object ConnectorEndpoints extends RestHelper{
inboundAdapterCallContextValue = InboundAdapterCallContext(cc.correlationId)
} yield {
// NOTE: if any filed type is BigDecimal, it is can't be serialized by lift json
- val json = Map((inboundAdapterCallContextKey, inboundAdapterCallContextValue),("data", toValueObject(data)))
+ val json = Map((inboundAdapterCallContextKey, inboundAdapterCallContextValue),("status", Status("",List(InboundStatusMessage("","","","")))),("data", toValueObject(data)))
(json, HttpCode.`200`(cc))
}
}
diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala
index 541e72781..b2a201bdd 100644
--- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala
@@ -11,6 +11,7 @@ import code.api.cache.Caching
import code.api.util.APIUtil.{OBPReturnType, isValidCurrencyISOCode, saveConnectorMetric, stringOrNull}
import code.api.util.ErrorMessages._
import code.api.util._
+import code.api.v3_1_0.AccountBalanceV310
import code.atms.Atms.Atm
import code.atms.MappedAtm
import code.bankconnectors.vJune2017.InboundAccountJune2017
@@ -437,19 +438,61 @@ object LocalMappedConnector extends Connector with MdcLoggable {
).map(bankAccount => (bankAccount, callContext))
}
- override def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : Future[Box[List[BankAccount]]] = {
+ override def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) = {
Future {
- Full(
+ (Full(
bankIdAccountIds.map(
bankIdAccountId =>
getBankAccount(
bankIdAccountId.bankId,
bankIdAccountId.accountId
).openOrThrowException(s"${ErrorMessages.BankAccountNotFound} current BANK_ID(${bankIdAccountId.bankId}) and ACCOUNT_ID(${bankIdAccountId.accountId})"))
- )
+ ),callContext)
}
}
+ override def getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) =
+ Future {
+ val accountsBalances = for{
+ bankIdAccountId <- bankIdAccountIds
+ bankAccount <- getBankAccount(bankIdAccountId.bankId, bankIdAccountId.accountId) ?~! s"${ErrorMessages.BankAccountNotFound} current BANK_ID(${bankIdAccountId.bankId}) and ACCOUNT_ID(${bankIdAccountId.accountId})"
+ accountBalance = AccountBalance(
+ id = bankAccount.accountId.value,
+ label = bankAccount.label,
+ bankId = bankAccount.bankId.value,
+ accountRoutings = bankAccount.accountRoutings.map(accountRounting => AccountRouting(accountRounting.scheme, accountRounting.address)),
+ balance = AmountOfMoney(bankAccount.currency, bankAccount.balance.toString())
+ )
+ } yield {
+ (accountBalance)
+ }
+
+ val allCurrencies = accountsBalances.map(_.balance.currency)
+ val mostCommonCurrency = if (allCurrencies.isEmpty) "EUR" else allCurrencies.groupBy(identity).mapValues(_.size).maxBy(_._2)._1
+
+ val allCommonCurrencyBalances = for {
+ accountBalance <- accountsBalances
+ requestAccountCurrency = accountBalance.balance.currency
+ requestAccountAmount = BigDecimal(accountBalance.balance.amount)
+ //From change from requestAccount Currency to mostCommon Currency
+ rate <- fx.exchangeRate(requestAccountCurrency, mostCommonCurrency)
+ requestChangedCurrencyAmount = fx.convert(requestAccountAmount, Some(rate))
+ }yield {
+ requestChangedCurrencyAmount
+ }
+
+ val overallBalance = allCommonCurrencyBalances.sum
+
+ (Full(AccountsBalances(
+ accounts = accountsBalances,
+ overallBalance = AmountOfMoney(
+ mostCommonCurrency,
+ overallBalance.toString
+ ),
+ overallBalanceDate = now
+ )), callContext)
+ }
+
override def checkBankAccountExistsLegacy(bankId: BankId, accountId: AccountId, callContext: Option[CallContext]) = {
getBankAccountLegacy(bankId: BankId, accountId: AccountId, callContext)
}
diff --git a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnectorBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnectorBuilder.scala
index cee6d76e6..5e8e0b2b7 100644
--- a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnectorBuilder.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnectorBuilder.scala
@@ -17,24 +17,22 @@ import code.api.util.CodeGenerateUtils.createDocExample
object RestConnectorBuilder extends App {
- val genMethodNames1 = List(
+ val genMethodNames = List(
// "getAdapterInfo",
- "getAdapterInfo",
+// "getAdapterInfo",
// "getUser", // have problem, return type not common
- // "getBanks",
- "getBanksFuture",
- // "getBank",
- "getBankFuture",
- // "getBankAccountsForUser",
- "getBankAccountsForUserFuture",
- "getCustomersByUserIdFuture",
- // "getBankAccount",
- // "checkBankAccountExists",
- "checkBankAccountExistsFuture",
+ "getBankAccountsBalances",
+// "getBanksLegacy",
+// "getBank",
+// "getBankLegacy",
+// "getBankAccountsForUser",
+// "getCustomersByUserIdFuture",
+// "getBankAccount",
+// "checkBankAccountExists",
// "getCoreBankAccounts",
- "getCoreBankAccountsFuture",
+// "getCoreBankAccountsFuture",
// "getTransactions",
- "getTransactionsCore",
+// "getTransactionsCore",
// "getTransaction",
// "getTransactionRequests210", //have problem params are not simple object
// "getCounterparties",
@@ -54,7 +52,7 @@ object RestConnectorBuilder extends App {
// "createCounterparty" // not support
)
//For vSept2018
- val genMethodNames = List(
+ val genMethodNames2 = List(
// "createOrUpdateKycCheck",
// "createOrUpdateKycDocument",
// "createOrUpdateKycMedia",
@@ -64,7 +62,7 @@ object RestConnectorBuilder extends App {
// "getKycMedias",
// "getKycStatuses",
// "createBankAccount",
- "createCustomer",
+// "createCustomer",
// "createMeeting",
// "createMessage"
)
diff --git a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala
index 554c2162d..e8e180986 100644
--- a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala
@@ -28,14 +28,13 @@ import java.util.UUID.randomUUID
import java.util.Date
import akka.http.scaladsl.model.{HttpProtocol, _}
+import akka.http.scaladsl.model.headers.RawHeader
import akka.util.ByteString
import code.api.APIFailureNewStyle
-import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions.inboundStatus
import code.api.cache.Caching
import code.api.util.APIUtil.{AdapterImplementation, MessageDoc, OBPReturnType, saveConnectorMetric}
import code.api.util.ErrorMessages._
-import code.api.util.ExampleValue._
-import code.api.util.{CallContext, OBPQueryParam}
+import code.api.util.{CallContext, NewStyle, OBPQueryParam}
import code.bankconnectors._
import code.bankconnectors.vJune2017.AuthInfo
import code.kafka.{KafkaHelper, Topics}
@@ -43,9 +42,8 @@ import code.util.AkkaHttpClient._
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.dto._
import com.openbankproject.commons.model._
-import com.tesobe.CacheKeyFromArguments
+import com.tesobe.{CacheKeyFromArguments, CacheKeyOmit}
import net.liftweb.common.{Box, Empty, _}
-import net.liftweb.json._
import net.liftweb.util.Helpers.tryo
import scala.collection.immutable.{List, Nil}
@@ -54,10 +52,11 @@ import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.reflect.runtime.universe._
-
import code.api.util.ExampleValue._
-
import code.api.util.APIUtil._
+import code.methodrouting.MethodRoutingParam
+import org.apache.commons.lang3.StringUtils
+import net.liftweb.json._
trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable {
//this one import is for implicit convert, don't delete
@@ -79,6 +78,7 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
val authInfoExample = AuthInfo(userId = "userId", username = "username", cbsToken = "cbsToken")
val errorCodeExample = "INTERNAL-OBP-ADAPTER-6001: ..."
+ val connectorName = "rest_vMar2019"
/*
All the following code is created automatclly.
@@ -166,16 +166,16 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
//---------------- dynamic start -------------------please don't modify this line
-// ---------- create on Thu Jun 13 11:07:28 CST 2019
+// ---------- create on Tue Jul 23 18:38:46 CEST 2019
messageDocs += MessageDoc(
- process = "obp.createCustomer",
+ process = "obp.getBankAccountsBalances",
messageFormat = messageFormat,
- description = "Create Customer",
- outboundTopic = Some(Topics.createTopicByClassName(OutBoundCreateCustomer.getClass.getSimpleName).request),
- inboundTopic = Some(Topics.createTopicByClassName(OutBoundCreateCustomer.getClass.getSimpleName).response),
+ description = "Get Bank Accounts Balances",
+ outboundTopic = None,
+ inboundTopic = None,
exampleOutboundMessage = (
- OutBoundCreateCustomer(outboundAdapterCallContext= OutboundAdapterCallContext(correlationId=correlationIdExample.value,
+ OutBoundGetBankAccountsBalances(outboundAdapterCallContext= OutboundAdapterCallContext(correlationId=correlationIdExample.value,
sessionId=Some(sessionIdExample.value),
consumerId=Some(consumerIdExample.value),
generalContext=Some(List( BasicGeneralContext(key=keyExample.value,
@@ -201,30 +201,11 @@ messageDocs += MessageDoc(
userOwners=List( InternalBasicUser(userId=userIdExample.value,
emailAddress=emailExample.value,
name=usernameExample.value))))))))),
- bankId=BankId(bankIdExample.value),
- legalName=legalNameExample.value,
- mobileNumber=mobileNumberExample.value,
- email=emailExample.value,
- faceImage= CustomerFaceImage(date=parseDate(customerFaceImageDateExample.value).getOrElse(sys.error("customerFaceImageDateExample.value is not validate date format.")),
- url=urlExample.value),
- dateOfBirth=parseDate(dateOfBirthExample.value).getOrElse(sys.error("dateOfBirthExample.value is not validate date format.")),
- relationshipStatus=relationshipStatusExample.value,
- dependents=dependentsExample.value.toInt,
- dobOfDependents=dobOfDependentsExample.value.split("[,;]").map(parseDate).flatMap(_.toSeq).toList,
- highestEducationAttained=highestEducationAttainedExample.value,
- employmentStatus=employmentStatusExample.value,
- kycStatus=kycStatusExample.value.toBoolean,
- lastOkDate=parseDate(outBoundCreateCustomerLastOkDateExample.value).getOrElse(sys.error("outBoundCreateCustomerLastOkDateExample.value is not validate date format.")),
- creditRating=Some( CreditRating(rating=ratingExample.value,
- source=sourceExample.value)),
- creditLimit=Some( AmountOfMoney(currency=currencyExample.value,
- amount=creditLimitAmountExample.value)),
- title=titleExample.value,
- branchId=branchIdExample.value,
- nameSuffix=nameSuffixExample.value)
+ bankIdAccountIds=List( BankIdAccountId(bankId=BankId(bankIdExample.value),
+ accountId=AccountId(accountIdExample.value))))
),
exampleInboundMessage = (
- InBoundCreateCustomer(inboundAdapterCallContext= InboundAdapterCallContext(correlationId=correlationIdExample.value,
+ InBoundGetBankAccountsBalances(inboundAdapterCallContext= InboundAdapterCallContext(correlationId=correlationIdExample.value,
sessionId=Some(sessionIdExample.value),
generalContext=Some(List( BasicGeneralContext(key=keyExample.value,
value=valueExample.value)))),
@@ -233,48 +214,42 @@ messageDocs += MessageDoc(
status=inboundStatusMessageStatusExample.value,
errorCode=inboundStatusMessageErrorCodeExample.value,
text=inboundStatusMessageTextExample.value))),
- data= CustomerCommons(customerId=customerIdExample.value,
+ data= AccountsBalances(accounts=List( AccountBalance(id=accountIdExample.value,
+ label=labelExample.value,
bankId=bankIdExample.value,
- number=customerNumberExample.value,
- legalName=legalNameExample.value,
- mobileNumber=mobileNumberExample.value,
- email=emailExample.value,
- faceImage= CustomerFaceImage(date=parseDate(customerFaceImageDateExample.value).getOrElse(sys.error("customerFaceImageDateExample.value is not validate date format.")),
- url=urlExample.value),
- dateOfBirth=parseDate(dateOfBirthExample.value).getOrElse(sys.error("dateOfBirthExample.value is not validate date format.")),
- relationshipStatus=relationshipStatusExample.value,
- dependents=dependentsExample.value.toInt,
- dobOfDependents=dobOfDependentsExample.value.split("[,;]").map(parseDate).flatMap(_.toSeq).toList,
- highestEducationAttained=highestEducationAttainedExample.value,
- employmentStatus=employmentStatusExample.value,
- creditRating= CreditRating(rating=ratingExample.value,
- source=sourceExample.value),
- creditLimit= CreditLimit(currency=currencyExample.value,
- amount=creditLimitAmountExample.value),
- kycStatus=kycStatusExample.value.toBoolean,
- lastOkDate=parseDate(customerLastOkDateExample.value).getOrElse(sys.error("customerLastOkDateExample.value is not validate date format.")),
- title=customerTitleExample.value,
- branchId=branchIdExample.value,
- nameSuffix=nameSuffixExample.value))
+ accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value,
+ address=accountRoutingAddressExample.value)),
+ balance= AmountOfMoney(currency=balanceCurrencyExample.value,
+ amount=balanceAmountExample.value))),
+ overallBalance= AmountOfMoney(currency=currencyExample.value,
+ amount="string"),
+ overallBalanceDate=new Date()))
),
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
- // url example: /createCustomer
- override def createCustomer(bankId: BankId, legalName: String, mobileNumber: String, email: String, faceImage: CustomerFaceImageTrait, dateOfBirth: Date, relationshipStatus: String, dependents: Int, dobOfDependents: List[Date], highestEducationAttained: String, employmentStatus: String, kycStatus: Boolean, lastOkDate: Date, creditRating: Option[CreditRatingTrait], creditLimit: Option[AmountOfMoneyTrait], title: String, branchId: String, nameSuffix: String, callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = {
- import net.liftweb.json.Serialization.write
-
- val url = getUrl("createCustomer")
- val outboundAdapterCallContext = Box(callContext.map(_.toOutboundAdapterCallContext)).openOrThrowException(NoCallContext)
- val jsonStr = write(OutBoundCreateCustomer(outboundAdapterCallContext , bankId, legalName, mobileNumber, email, faceImage, dateOfBirth, relationshipStatus, dependents, dobOfDependents, highestEducationAttained, employmentStatus, kycStatus, lastOkDate, creditRating, creditLimit, title, branchId, nameSuffix))
- sendPostRequest[InBoundCreateCustomer](url, callContext, jsonStr)
- .map{ boxedResult =>
- boxedResult match {
- case Full(result) => (Full(result.data), buildCallContext(result.inboundAdapterCallContext, callContext))
- case result: EmptyBox => (result, callContext) // Empty and Failure all match this case
- }
+ // url example: /getBankAccountsBalances/bankIdAccountIds/{bankIdAccountIds}
+ override def getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], @CacheKeyOmit callContext: Option[CallContext]): OBPReturnType[Box[AccountsBalances]] = saveConnectorMetric {
+ /**
+ * Please note that "var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)"
+ * is just a temporary value filed with UUID values in order to prevent any ambiguity.
+ * The real value will be assigned by Macro during compile time at this line of a code:
+ * https://github.com/OpenBankProject/scala-macros/blob/master/macros/src/main/scala/com/tesobe/CacheKeyFromArgumentsMacro.scala#L49
+ */
+ var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
+ CacheKeyFromArguments.buildCacheKey {
+ Caching.memoizeWithProvider(Some(cacheKey.toString()))(banksTTL second){
+ val url = getUrl("getBankAccountsBalances" , ("bankIdAccountIds", bankIdAccountIds))
+ sendGetRequest[InBoundGetBankAccountsBalances](url, callContext)
+ .map { boxedResult =>
+ boxedResult match {
+ case Full(result) => (Full(result.data), buildCallContext(result.inboundAdapterCallContext, callContext))
+ case result: EmptyBox => (result, callContext) // Empty and Failure all match this case
+ }
+ }
+ }
}
- }
+ }("getBankAccountsBalances")
//---------------- dynamic end ---------------------please don't modify this line
@@ -282,6 +257,7 @@ messageDocs += MessageDoc(
+
private[this] def sendGetRequest[T: TypeTag : Manifest](url: String, callContext: Option[CallContext]) =
@@ -296,8 +272,12 @@ messageDocs += MessageDoc(
private[this] def sendDelteRequest[T: TypeTag : Manifest](url: String, callContext: Option[CallContext]) =
sendRequest[T](url, callContext, HttpMethods.DELETE)
- //TODO every connector should implement this method to build authorization headers with callContext
- private[this] implicit def buildHeaders(callContext: Option[CallContext]): List[HttpHeader] = Nil
+ //In RestConnector, we use the headers to propagate the parameters to Adapter. The parameters come from the CallContext.outboundAdapterAuthInfo.userAuthContext
+ //We can set them from UserOauthContext or the http request headers.
+ private[this] implicit def buildHeaders(callContext: Option[CallContext]): List[HttpHeader] = {
+ val generalContext = callContext.flatMap(_.toOutboundAdapterCallContext.generalContext).getOrElse(List.empty[BasicGeneralContext])
+ generalContext.map(generalContext => RawHeader(generalContext.key,generalContext.value))
+ }
private[this] def buildAdapterCallContext(callContext: Option[CallContext]): OutboundAdapterCallContext = callContext.map(_.toOutboundAdapterCallContext).orNull
@@ -314,6 +294,17 @@ messageDocs += MessageDoc(
private[this] val baseUrl = "http://localhost:8080/restConnector"
private[this] def getUrl(methodName: String, variables: (String, Any)*): String = {
+ // rest connector can have url value in the parameters, key is url
+ val urlInMethodRouting = NewStyle.function.getMethodRoutings(Some(methodName))
+ .flatMap(_.parameters).flatten
+ .find(_.key == "url")
+ .map(_.value)
+
+
+ if(urlInMethodRouting.isDefined) {
+ return urlInMethodRouting.get
+ }
+
// convert any type value to string, to fill in the url
def urlValueConverter(obj: Any):String = {
val value = obj match {
@@ -341,6 +332,7 @@ messageDocs += MessageDoc(
private[this] def sendRequest[T: TypeTag : Manifest](url: String, callContext: Option[CallContext], method: HttpMethod, entityJsonString: String = ""): Future[Box[T]] = {
val request = prepareHttpRequest(url, method, HttpProtocol("HTTP/1.1"), entityJsonString).withHeaders(callContext)
+ logger.debug(s"RestConnector_vMar2019 request is : $request")
val responseFuture = makeHttpRequest(request)
val jsonType = typeOf[T]
responseFuture.map {
diff --git a/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala b/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala
index a475477ee..102846182 100644
--- a/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala
+++ b/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala
@@ -1,12 +1,15 @@
package code.methodrouting
+import code.api.util.CustomJsonFormats
import code.util.MappedUUID
import net.liftweb.common.{Box, Empty, EmptyBox, Full}
+import net.liftweb.json
import net.liftweb.mapper._
import net.liftweb.util.Helpers.tryo
import org.apache.commons.lang3.StringUtils
+import net.liftweb.json.Serialization.write
-object MappedMethodRoutingProvider extends MethodRoutingProvider {
+object MappedMethodRoutingProvider extends MethodRoutingProvider with CustomJsonFormats{
override def getById(methodRoutingId: String): Box[MethodRoutingT] = MethodRouting.find(
By(MethodRouting.MethodRoutingId, methodRoutingId)
@@ -42,12 +45,18 @@ object MappedMethodRoutingProvider extends MethodRoutingProvider {
// if not supply bankIdPattern, isExactMatch must be false
val isExactMatch = if(bankIdPattern.isDefined) methodRouting.isBankIdExactMatch else false
+ val existsMethodRoutingParameters = methodRouting.parameters match {
+ case Some(parameters) if (parameters.nonEmpty) => parameters
+ case _ => List.empty[MethodRoutingParam]
+ }
+
tryo{
entityToPersist
.MethodName(methodRouting.methodName)
.BankIdPattern(bankIdPattern.orNull)
.IsBankIdExactMatch(isExactMatch)
.ConnectorName(methodRouting.connectorName)
+ .Parameters(write(existsMethodRoutingParameters))
.saveMe()
}
}
@@ -59,7 +68,7 @@ object MappedMethodRoutingProvider extends MethodRoutingProvider {
}
-class MethodRouting extends MethodRoutingT with LongKeyedMapper[MethodRouting] with IdPK {
+class MethodRouting extends MethodRoutingT with LongKeyedMapper[MethodRouting] with IdPK with CustomJsonFormats{
override def getSingleton = MethodRouting
@@ -70,12 +79,16 @@ class MethodRouting extends MethodRoutingT with LongKeyedMapper[MethodRouting] w
}
object IsBankIdExactMatch extends MappedBoolean(this)
object ConnectorName extends MappedString(this, 255)
+ object Parameters extends MappedString(this, 5000)
override def methodRoutingId: Option[String] = Option(MethodRoutingId.get)
override def methodName: String = MethodName.get
override def bankIdPattern: Option[String] = Option(BankIdPattern.get)
override def isBankIdExactMatch: Boolean = IsBankIdExactMatch.get
override def connectorName: String = ConnectorName.get
+
+ //Here we store all the key-value paris in one big String filed in database.
+ override def parameters: Option[List[MethodRoutingParam]] = Option(json.parse(if (Parameters.get != null) Parameters.get else "[]").extract[List[MethodRoutingParam]])
}
object MethodRouting extends MethodRouting with LongKeyedMetaMapper[MethodRouting] {
diff --git a/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala b/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala
index 4c8ff4e18..c9dacef44 100644
--- a/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala
+++ b/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala
@@ -24,17 +24,21 @@ trait MethodRoutingT {
*/
def isBankIdExactMatch: Boolean
def connectorName: String
+ def parameters: Option[List[MethodRoutingParam]]
}
case class MethodRoutingCommons(methodName: String,
connectorName: String,
isBankIdExactMatch: Boolean,
bankIdPattern: Option[String],
- methodRoutingId: Option[String] = None
+ parameters: Option[List[MethodRoutingParam]] = None,
+ methodRoutingId: Option[String] = None,
) extends MethodRoutingT with JsonFieldReName
object MethodRoutingCommons extends Converter[MethodRoutingT, MethodRoutingCommons]
+case class MethodRoutingParam(key: String, value: String)
+
trait MethodRoutingProvider {
def getById(methodRoutingId: String): Box[MethodRoutingT]
diff --git a/obp-api/src/main/scala/code/model/dataAccess/MappedBankAccount.scala b/obp-api/src/main/scala/code/model/dataAccess/MappedBankAccount.scala
index e41247f21..a2a8139d7 100644
--- a/obp-api/src/main/scala/code/model/dataAccess/MappedBankAccount.scala
+++ b/obp-api/src/main/scala/code/model/dataAccess/MappedBankAccount.scala
@@ -31,7 +31,8 @@ class MappedBankAccount extends BankAccount with LongKeyedMapper[MappedBankAccou
object accountLabel extends MappedString(this, 255)
- //the last time this account was updated via hbci
+ //the last time this account was updated via hbci [when transaction data was refreshed from the bank.]
+ //It means last transaction refresh date only used for HBCI now.
object accountLastUpdate extends MappedDateTime(this)
object mAccountRoutingScheme extends MappedString(this, 32)
diff --git a/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala b/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
index 47d9224e4..8d9a86aa7 100644
--- a/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
+++ b/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
@@ -15,7 +15,7 @@ import net.liftweb.mapper._
*/
object MappedWebUiPropsProvider extends WebUiPropsProvider {
// default webUiProps value cached seconds
- private val webUiPropsTTL = APIUtil.getPropsAsIntValue("webui.props.cache.ttl.seconds", 20)
+ private val webUiPropsTTL = APIUtil.getPropsAsIntValue("webui.props.cache.ttl.seconds", 0)
override def getAll(): List[WebUiPropsT] = WebUiProps.findAll()
diff --git a/obp-api/src/main/scripts/migrate/migrate_00000018.sql b/obp-api/src/main/scripts/migrate/migrate_00000018.sql
new file mode 100644
index 000000000..6912215c9
--- /dev/null
+++ b/obp-api/src/main/scripts/migrate/migrate_00000018.sql
@@ -0,0 +1 @@
+ALTER TABLE "methodrouting" ADD "parameters" varchar(5000) NULL;
diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala
new file mode 100644
index 000000000..8f62d51a8
--- /dev/null
+++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala
@@ -0,0 +1,277 @@
+package code.api.v3_1_0
+
+import net.liftweb.json.JValue
+import org.scalatest.Tag
+import io.swagger.parser.OpenAPIParser
+import java.util
+import code.api.ResourceDocs1_4_0.ResourceDocsV140ServerSetup
+import code.api.util.{ApiVersion, CustomJsonFormats}
+import code.api.v1_4_0.JSONFactory1_4_0.ImplementedByJson
+import net.liftweb.json
+
+import scala.collection.immutable.List
+class ResourceDocsTest extends ResourceDocsV140ServerSetup with CustomJsonFormats{
+
+ object VersionOfApi extends Tag(ApiVersion.v1_4_0.toString)
+ object ApiEndpoint1 extends Tag("Get Swagger ResourceDoc")
+ object ApiEndpoint2 extends Tag("Get OBP ResourceDoc ")
+
+
+ feature(s"test ${ApiEndpoint1.name} ") {
+
+ case class RoleJson (
+ role: String,
+ requires_bank_id: Boolean
+ )
+
+ //This case class is for API_Explorer, it should make sure api_explorer can get proper doc.
+ case class ResourceDocJson(operation_id: String,
+ request_verb: String,
+ request_url: String,
+ summary: String, // Summary of call should be 120 characters max
+ description: String, // Description of call in markdown
+ example_request_body: JValue, // An example request body
+ success_response_body: JValue, // Success response body
+ error_response_bodies: List[String],
+ implemented_by: ImplementedByJson,
+ is_core : Boolean,
+ is_psd2 : Boolean,
+ is_obwg : Boolean, // This may be tracking isCore
+ tags : List[String],
+ roles: List[RoleJson],
+ is_featured: Boolean,
+ special_instructions: String,
+ specified_url: String // This is the URL that we want people to call.
+ )
+
+ case class ResourceDocsJson (resource_docs : List[ResourceDocJson])
+
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v4.0.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v4.0.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v3.1.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.1.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v3.0.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.0.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v2.2.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.2.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v2.1.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.1.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v2.0.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.0.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v1.4.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.4.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v1.3.0", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.3.0" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+
+ scenario(s"We will test ${ApiEndpoint1.name} Api -v1.2.1", ApiEndpoint1, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.2.1" / "obp").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ responseGetObp.body.extract[ResourceDocsJson]
+ }
+ }
+
+ feature(s"test ${ApiEndpoint2.name} ") {
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v4.0.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v4.0.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ if (!errors.isEmpty) logger.info(s"Here is the wrong swagger json: $swaggerJsonString")
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v3.1.1", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.1.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v3.0.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.0.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v2.2.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.2.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v2.1.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.1.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v2.0.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.0.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v1.4.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.4.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v1.3.0", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.3.0" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ scenario(s"We will test ${ApiEndpoint2.name} Api - v1.2.1", ApiEndpoint2, VersionOfApi) {
+ val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.2.1" / "swagger").GET
+ val responseGetObp = makeGetRequest(requestGetObp)
+ And("We should get 200 and the response can be extract to case classes")
+ responseGetObp.code should equal(200)
+ val swaggerJsonString = json.compactRender(responseGetObp.body)
+
+ val validatedSwaggerResult = ValidateSwaggerString(swaggerJsonString)
+ val errors = validatedSwaggerResult._1
+ errors.isEmpty should be (true)
+ }
+
+ }
+
+
+
+
+ //Note: it is tricky to validate the swagger string, I just find this : https://github.com/swagger-api/swagger-parser/issues/718
+ //So follow it to call the `Validate` method:
+ //https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Validate.java#L46
+ def ValidateSwaggerString (swaggerJsonString: String)= {
+ val result = new OpenAPIParser().readContents(swaggerJsonString, null, null)
+ val messageList: util.List[String] = result.getMessages()
+
+ val errors = new util.HashSet[String](messageList)
+ val warnings = new util.HashSet[String]
+
+ val sb = new StringBuilder
+
+ if (!errors.isEmpty) {
+ sb.append("Errors:").append(System.lineSeparator)
+ errors.forEach((msg: String) => sb.append("\t-").append(msg).append(System.lineSeparator))
+ }
+
+ if (!warnings.isEmpty) {
+ sb.append("Warnings: ").append(System.lineSeparator)
+ warnings.forEach((msg: String) => sb.append("\t-").append(msg).append(System.lineSeparator))
+ }
+
+ if (!errors.isEmpty) {
+ sb.append(System.lineSeparator)
+ sb.append("[error] Spec has ").append(errors.size).append(" errors.")
+ System.err.println(sb.toString)
+ System.exit(1)
+ }
+ else if (!warnings.isEmpty) {
+ sb.append(System.lineSeparator)
+ sb.append("[info] Spec has ").append(warnings.size).append(" recommendation(s).")
+ }
+ else { // we say "issues" here rather than "errors" to account for both errors and issues.
+ sb.append("No validation issues detected.")
+ }
+ val allMessages = sb.toString
+ logger.info(s"validatedSwaggerResult.errors $errors")
+ logger.info(s"validatedSwaggerResult.warnings $warnings")
+ logger.info(s"validatedSwaggerResult.allMessages $allMessages")
+
+ (errors, warnings, allMessages)
+ }
+}
diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsV140ServerSetup.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsV140ServerSetup.scala
new file mode 100644
index 000000000..8757152ae
--- /dev/null
+++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsV140ServerSetup.scala
@@ -0,0 +1,15 @@
+package code.api.ResourceDocs1_4_0
+
+import code.setup.ServerSetupWithTestData
+
+trait ResourceDocsV140ServerSetup extends ServerSetupWithTestData {
+
+ def ResourceDocsV1_4Request = baseRequest / "obp" / "v1.4.0"
+ def ResourceDocsV2_0Request = baseRequest / "obp" / "v2.0.0"
+ def ResourceDocsV2_1Request = baseRequest / "obp" / "v2.1.0"
+ def ResourceDocsV2_2Request = baseRequest / "obp" / "v2.2.0"
+ def ResourceDocsV3_0Request = baseRequest / "obp" / "v3.0.0"
+ def ResourceDocsV3_1Request = baseRequest / "obp" / "v3.1.0"
+ def ResourceDocsV4_0Request = baseRequest / "obp" / "v4.0.0"
+
+}
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
index d05b03c8c..41093c5da 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala
@@ -20,6 +20,7 @@ class AccountTest extends V310ServerSetup with DefaultUsers {
object VersionOfApi extends Tag(ApiVersion.v3_1_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations3_1_0.updateAccount))
object ApiEndpoint2 extends Tag(nameOf(Implementations3_1_0.createAccount))
+ object ApiEndpoint3 extends Tag(nameOf(Implementations3_1_0.getBankAccountsBalances))
lazy val testBankId = testBankId1
lazy val putCreateAccountJSONV310 = SwaggerDefinitionsJSON.createAccountJSONV220.copy(user_id = resourceUser1.userId)
@@ -119,4 +120,19 @@ class AccountTest extends V310ServerSetup with DefaultUsers {
}
+ feature(s"test ${ApiEndpoint3.name}") {
+ scenario("We will test ${ApiEndpoint3.name}", ApiEndpoint3, VersionOfApi) {
+ Given("The test bank and test accounts")
+ val requestGet = (v3_1_0_Request / "banks" / testBankId.value / "balances").GET <@ (user1)
+
+ val responseGet = makeGetRequest(requestGet)
+ responseGet.code should equal(200)
+ responseGet.body.extract[AccountsBalancesV310Json].accounts.size > 0 should be (true)
+ responseGet.body.extract[AccountsBalancesV310Json].overall_balance.currency.nonEmpty should be (true)
+ responseGet.body.extract[AccountsBalancesV310Json].overall_balance.amount.nonEmpty should be (true)
+ responseGet.body.extract[AccountsBalancesV310Json].overall_balance_date.getTime >0 should be (true)
+
+ }
+ }
+
}
diff --git a/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
index 7a2d8112e..678a7aea1 100644
--- a/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
+++ b/obp-api/src/test/scala/code/api/v3_1_0/MethodRoutingTest.scala
@@ -32,11 +32,13 @@ import code.api.util.ApiVersion
import code.api.util.ErrorMessages._
import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
import code.entitlement.Entitlement
-import code.methodrouting.MethodRoutingCommons
+import code.methodrouting.{MethodRoutingCommons, MethodRoutingParam}
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
+import scala.collection.immutable.List
+
class MethodRoutingTest extends V310ServerSetup {
/**
@@ -52,7 +54,7 @@ class MethodRoutingTest extends V310ServerSetup {
object ApiEndpoint3 extends Tag(nameOf(Implementations3_1_0.getMethodRoutings))
object ApiEndpoint4 extends Tag(nameOf(Implementations3_1_0.deleteMethodRouting))
- val rightEntity = MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"))
+ val rightEntity = MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))))
val wrongEntity = MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_([")) // wrong regex
diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala
index c85cf4392..17b6ec4fe 100644
--- a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala
+++ b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala
@@ -84,6 +84,10 @@ case class OutBoundGetCoreBankAccounts(outboundAdapterCallContext: OutboundAdapt
bankIdAccountIds: List[BankIdAccountId]) extends TopicTrait
case class InBoundGetCoreBankAccounts(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[CoreAccount]) extends InBoundTrait[List[CoreAccount]]
+case class OutBoundGetBankAccountsBalances(outboundAdapterCallContext: OutboundAdapterCallContext,
+ bankIdAccountIds: List[BankIdAccountId]) extends TopicTrait
+
+case class InBoundGetBankAccountsBalances(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: AccountsBalances) extends InBoundTrait[AccountsBalances]
case class OutBoundGetCoreBankAccountsHeld(outboundAdapterCallContext: OutboundAdapterCallContext,
bankIdAccountIds: List[BankIdAccountId]) extends TopicTrait
diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala
index 647d6e89a..d8cac21fc 100644
--- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala
+++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala
@@ -184,6 +184,7 @@ trait BankAccount{
def iban : Option[String]
def number : String
def bankId : BankId
+ //It means last transaction refresh date only used for HBCI now.
def lastUpdate : Date
def branchId: String
def accountRoutingScheme: String
@@ -298,6 +299,20 @@ case class CoreAccount(
accountRoutings: List[AccountRouting]
)
+case class AccountBalance(
+ id: String,
+ label: String,
+ bankId: String,
+ accountRoutings: List[AccountRouting],
+ balance: AmountOfMoney
+)
+
+case class AccountsBalances(
+ accounts: List[AccountBalance],
+ overallBalance: AmountOfMoney,
+ overallBalanceDate: Date
+)
+
case class AccountHeld(
id: String,
bankId: String,