feature/Add fields optional in POST Bank

This commit is contained in:
Marko Milić 2022-09-16 16:06:11 +02:00
parent afc46603f1
commit 2b04b7c97b
4 changed files with 253 additions and 6 deletions

View File

@ -866,6 +866,25 @@ object SwaggerDefinitionsJSON {
website = "www.openbankproject.com",
bank_routings = List(bankRoutingJsonV121),
attributes = Some(List(bankAttributeBankResponseJsonV400))
)
val bankJson500 = BankJson500(
id = "gh.29.uk",
bank_code = "bank_code ",
full_name = "full_name",
logo = "logo",
website = "www.openbankproject.com",
bank_routings = List(bankRoutingJsonV121),
attributes = Some(List(bankAttributeBankResponseJsonV400))
)
val postBankJson500 = PostBankJson500(
id = Some("gh.29.uk"),
bank_code = "bank_code",
full_name = Some("full_name"),
logo = Some("logo"),
website = Some("www.openbankproject.com"),
bank_routings = Some(List(bankRoutingJsonV121)),
attributes = Some(List(bankAttributeBankResponseJsonV400))
)
val banksJSON400 = BanksJson400(

View File

@ -2,15 +2,16 @@ package code.api.v5_0_0
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil._
import code.api.util.ApiRole.{CanCreateUserAuthContextUpdate, canCreateUserAuthContext, canGetCustomers, canGetCustomersMinimal, canGetUserAuthContext}
import code.api.util.ApiRole.{CanCreateEntitlementAtOneBank, CanCreateUserAuthContextUpdate, CanReadDynamicResourceDocsAtOneBank, canCreateBank, canCreateUserAuthContext, canGetCustomers, canGetCustomersMinimal, canGetUserAuthContext}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.api.util.{APIUtil, ApiRole, Consent, NewStyle}
import code.api.util.{APIUtil, ApiRole, Consent, ErrorMessages, NewStyle}
import code.api.util.NewStyle.HttpCode
import code.api.util.NewStyle.function.extractQueryParams
import code.api.v2_1_0.JSONFactory210
import code.api.v3_0_0.JSONFactory300
import code.api.v3_1_0.{PostConsentBodyCommonJson, PostConsentEmailJsonV310, PostConsentEntitlementJsonV310, PostConsentPhoneJsonV310, PostConsentViewJsonV310, PostUserAuthContextJson, PostUserAuthContextUpdateJsonV310}
import code.api.v4_0_0.{BankJson400, JSONFactory400}
import code.api.v4_0_0.JSONFactory400.createCustomersMinimalJson
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
@ -27,7 +28,7 @@ import net.liftweb.common.Full
import net.liftweb.http.Req
import net.liftweb.http.rest.RestHelper
import net.liftweb.json
import net.liftweb.json.{compactRender}
import net.liftweb.json.compactRender
import net.liftweb.util.Props
import scala.collection.immutable.{List, Nil}
@ -64,6 +65,90 @@ trait APIMethods500 {
val apiRelations = ArrayBuffer[ApiRelation]()
val codeContext = CodeContext(staticResourceDocs, apiRelations)
staticResourceDocs += ResourceDoc(
createBank,
implementedInApiVersion,
"createBank",
"POST",
"/banks",
"Create Bank",
s"""Create a new bank (Authenticated access).
|
|The user creating this will be automatically assigned the Role CanCreateEntitlementAtOneBank.
|Thus the User can manage the bank they create and assign Roles to other Users.
|
|Only SANDBOX mode
|The settlement accounts are created specified by the bank in the POST body.
|Name and account id are created in accordance to the next rules:
| - Incoming account (name: Default incoming settlement account, Account ID: OBP_DEFAULT_INCOMING_ACCOUNT_ID, currency: EUR)
| - Outgoing account (name: Default outgoing settlement account, Account ID: OBP_DEFAULT_OUTGOING_ACCOUNT_ID, currency: EUR)
|
|""",
postBankJson500,
bankJson500,
List(
InvalidJsonFormat,
$UserNotLoggedIn,
InsufficientAuthorisationToCreateBank,
UnknownError
),
List(apiTagBank, apiTagNewStyle),
Some(List(canCreateBank))
)
lazy val createBank: OBPEndpoint = {
case "banks" :: Nil JsonPost json -> _ => {
cc =>
val failMsg = s"$InvalidJsonFormat The Json body should be the $BankJson400 "
for {
bank <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
json.extract[PostBankJson500]
}
_ <- Helper.booleanToFuture(failMsg = ErrorMessages.InvalidConsumerCredentials, cc=cc.callContext) {
cc.callContext.map(_.consumer.isDefined == true).isDefined
}
_ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", cc=cc.callContext) {
bank.id.forall(_.length > 3)
}
_ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat BANK_ID can not contain space characters", cc=cc.callContext) {
!bank.id.contains(" ")
}
(success, callContext) <- NewStyle.function.createOrUpdateBank(
bank.id.getOrElse(APIUtil.generateUUID()),
bank.full_name.getOrElse(""),
bank.bank_code,
bank.logo.getOrElse(""),
bank.website.getOrElse(""),
bank.bank_routings.getOrElse(Nil).find(_.scheme == "BIC").map(_.address).getOrElse(""),
"",
bank.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.scheme).getOrElse(""),
bank.bank_routings.getOrElse(Nil).filterNot(_.scheme == "BIC").headOption.map(_.address).getOrElse(""),
cc.callContext
)
entitlements <- NewStyle.function.getEntitlementsByUserId(cc.userId, callContext)
entitlementsByBank = entitlements.filter(_.bankId==bank.id.getOrElse(""))
_ <- entitlementsByBank.filter(_.roleName == CanCreateEntitlementAtOneBank.toString()).size > 0 match {
case true =>
// Already has entitlement
Future()
case false =>
Future(Entitlement.entitlement.vend.addEntitlement(bank.id.getOrElse(""), cc.userId, CanCreateEntitlementAtOneBank.toString()))
}
_ <- entitlementsByBank.filter(_.roleName == CanReadDynamicResourceDocsAtOneBank.toString()).size > 0 match {
case true =>
// Already has entitlement
Future()
case false =>
Future(Entitlement.entitlement.vend.addEntitlement(bank.id.getOrElse(""), cc.userId, CanReadDynamicResourceDocsAtOneBank.toString()))
}
} yield {
(JSONFactory500.createBankJSON500(success), HttpCode.`201`(callContext))
}
}
}
staticResourceDocs += ResourceDoc(
createUserAuthContext,
implementedInApiVersion,

View File

@ -26,13 +26,38 @@
*/
package code.api.v5_0_0
import code.api.v3_1_0.{PostConsentEntitlementJsonV310}
import com.openbankproject.commons.model.{AccountRoutingJsonV121, UserAuthContext, UserAuthContextUpdate}
import code.api.v3_1_0.PostConsentEntitlementJsonV310
import com.openbankproject.commons.model.{AccountRoutingJsonV121, Bank, UserAuthContext, UserAuthContextUpdate}
import net.liftweb.json.JsonAST.JValue
import java.util.Date
import code.api.util.APIUtil.stringOrNull
import code.api.v1_2_1.BankRoutingJsonV121
import code.api.v4_0_0.{BankAttributeBankResponseJsonV400, BankJson400}
import code.bankattribute.BankAttribute
import scala.collection.immutable.List
case class PostBankJson500(
id: Option[String],
bank_code: String,
full_name: Option[String],
logo: Option[String],
website: Option[String],
bank_routings: Option[List[BankRoutingJsonV121]],
attributes: Option[List[BankAttributeBankResponseJsonV400]]
)
case class BankJson500(
id: String,
bank_code: String,
full_name: String,
logo: String,
website: String,
bank_routings: List[BankRoutingJsonV121],
attributes: Option[List[BankAttributeBankResponseJsonV400]]
)
case class UserAuthContextJsonV500(
user_auth_context_id: String,
user_id: String,
@ -109,5 +134,30 @@ object JSONFactory500 {
consumer_id = userAuthContextUpdate.consumerId
)
}
def createBankJSON500(bank: Bank, attributes: List[BankAttribute] = Nil): BankJson500 = {
val obp = BankRoutingJsonV121("OBP", bank.bankId.value)
val bic = BankRoutingJsonV121("BIC", bank.swiftBic)
val routings = bank.bankRoutingScheme match {
case "OBP" => bic :: BankRoutingJsonV121(bank.bankRoutingScheme, bank.bankRoutingAddress) :: Nil
case "BIC" => obp :: BankRoutingJsonV121(bank.bankRoutingScheme, bank.bankRoutingAddress) :: Nil
case _ => obp :: bic :: BankRoutingJsonV121(bank.bankRoutingScheme, bank.bankRoutingAddress) :: Nil
}
new BankJson500(
stringOrNull(bank.bankId.value),
stringOrNull(bank.shortName),
stringOrNull(bank.fullName),
stringOrNull(bank.logoUrl),
stringOrNull(bank.websiteUrl),
routings.filter(a => stringOrNull(a.address) != null),
Option(
attributes.filter(_.isActive == Some(true)).map(a => BankAttributeBankResponseJsonV400(
name = a.name,
value = a.value)
)
)
)
}
}

View File

@ -0,0 +1,93 @@
package code.api.v5_0_0
import code.api.Constant.{INCOMING_SETTLEMENT_ACCOUNT_ID, OUTGOING_SETTLEMENT_ACCOUNT_ID}
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.postBankJson500
import code.api.util.ApiRole.CanCreateBank
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.api.util.{ApiRole, ErrorMessages, NewStyle}
import code.api.util.APIUtil.OAuth._
import code.api.v5_0_0.APIMethods500.Implementations5_0_0
import code.entitlement.Entitlement
import code.setup.{APIResponse, DefaultUsers}
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AccountId, BankId, ErrorMessage}
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
class BankTests extends V500ServerSetupAsync with DefaultUsers {
override def beforeAll() {
super.beforeAll()
}
override def afterAll() {
super.afterAll()
}
/**
* Test tags
* Example: To run tests with tag "getPermissions":
* mvn test -D tagsToInclude
*
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations5_0_0.createBank))
feature(s"Assuring that endpoint createBank works as expected - $VersionOfApi") {
scenario("We try to consume endpoint createBank - Anonymous access", ApiEndpoint1, VersionOfApi) {
When("We make the request")
val request = (v5_0_0_Request / "banks").POST
val response = makePostRequestAsync(request, write(postBankJson500))
Then("We should get a 401")
And("We should get a message: " + ErrorMessages.UserNotLoggedIn)
response map { r =>
r.code should equal(401)
r.body.extract[ErrorMessage].message should equal(ErrorMessages.UserNotLoggedIn)
}
}
scenario("We try to consume endpoint createBank without proper role - Authorized access", ApiEndpoint1, VersionOfApi) {
When("We make the request")
val request = (v5_0_0_Request / "banks").POST <@ (user1)
val response = makePostRequestAsync(request, write(postBankJson500))
Then("We should get a 403")
And("We should get a message: " + s"$CanCreateBank entitlement required")
response map { r =>
r.code should equal(403)
r.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanCreateBank)
}
}
scenario("We try to consume endpoint createBank with proper role - Authorized access", ApiEndpoint1, VersionOfApi) {
When("We add required entitlement")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanCreateBank.toString)
And("We make the request")
val requestGet = (v5_0_0_Request / "banks").POST <@ (user1)
val response = for {
before <- NewStyle.function.getEntitlementsByUserId(resourceUser1.userId, None) map {
_.exists( e => e.roleName == ApiRole.CanCreateEntitlementAtOneBank.toString && e.bankId == postBankJson500.id.getOrElse(""))
}
response: APIResponse <- makePostRequestAsync(requestGet, write(postBankJson500))
after <- NewStyle.function.getEntitlementsByUserId(resourceUser1.userId, None) map {
_.exists( e => e.roleName == ApiRole.CanCreateEntitlementAtOneBank.toString && e.bankId == postBankJson500.id.getOrElse(""))
}
} yield (before, after, response)
Then("We should get a 201")
response flatMap { r =>
r._1 should equal(false) // Before we create a bank there is no role CanCreateEntitlementAtOneBank
r._2 should equal(true) // After we create a bank there is a role CanCreateEntitlementAtOneBank
r._3.code should equal(201)
Then("Default settlement accounts should be created")
val defaultOutgoingAccount = NewStyle.function.checkBankAccountExists(BankId(postBankJson500.id.getOrElse("")), AccountId(OUTGOING_SETTLEMENT_ACCOUNT_ID), None)
val defaultIncomingAccount = NewStyle.function.checkBankAccountExists(BankId(postBankJson500.id.getOrElse("")), AccountId(INCOMING_SETTLEMENT_ACCOUNT_ID), None)
defaultOutgoingAccount.map(account => account._1.accountId.value should equal(OUTGOING_SETTLEMENT_ACCOUNT_ID))
defaultIncomingAccount.map(account => account._1.accountId.value should equal(INCOMING_SETTLEMENT_ACCOUNT_ID))
}
}
}
}