feature/Add endpoint createProduct v5.0.0

This commit is contained in:
Marko Milić 2022-09-22 13:18:27 +02:00
parent 6ca3afa1b7
commit 669d09af7c
5 changed files with 297 additions and 3 deletions

View File

@ -4623,6 +4623,14 @@ object SwaggerDefinitionsJSON {
description = descriptionExample.value,
meta = metaJson,
)
val putProductJsonV500 = PutProductJsonV500(
parent_product_code = parentProductCodeExample.value,
name = productNameExample.value,
more_info_url = Some(moreInfoUrlExample.value),
terms_and_conditions_url = Some(termsAndConditionsUrlExample.value),
description = Some(descriptionExample.value),
meta = Some(metaJson)
)
val createMessageJsonV400 = CreateMessageJsonV400(
message = messageExample.value,

View File

@ -12,6 +12,7 @@ import code.api.v2_1_0.JSONFactory210
import code.api.v3_0_0.JSONFactory300
import code.api.v3_1_0._
import code.api.v4_0_0.JSONFactory400.createCustomersMinimalJson
import code.api.v4_0_0.{JSONFactory400, PutProductJsonV400}
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
import code.entitlement.Entitlement
@ -21,9 +22,9 @@ import code.views.Views
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication
import com.openbankproject.commons.model.{BankId, CreditLimit, CreditRating, CustomerFaceImage, UserAuthContextUpdateStatus}
import com.openbankproject.commons.model.{BankId, CreditLimit, CreditRating, CustomerFaceImage, ProductCode, UserAuthContextUpdateStatus}
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.common.Full
import net.liftweb.common.{Empty, Full}
import net.liftweb.http.Req
import net.liftweb.http.rest.RestHelper
import net.liftweb.json
@ -1019,6 +1020,86 @@ trait APIMethods500 {
}
}
staticResourceDocs += ResourceDoc(
createProduct,
implementedInApiVersion,
nameOf(createProduct),
"PUT",
"/banks/BANK_ID/products/PRODUCT_CODE",
"Create Product",
s"""Create or Update Product for the Bank.
|
|
|Typical Super Family values / Asset classes are:
|
|Debt
|Equity
|FX
|Commodity
|Derivative
|
|$productHiearchyAndCollectionNote
|
|
|${authenticationRequiredMessage(true) }
|
|
|""",
putProductJsonV500,
productJsonV400.copy(attributes = None, fees = None),
List(
$UserNotLoggedIn,
$BankNotFound,
UserHasMissingRoles,
UnknownError
),
List(apiTagProduct, apiTagNewStyle),
Some(List(canCreateProduct, canCreateProductAtAnyBank))
)
lazy val createProduct: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonPut json -> _ => {
cc =>
for {
(Full(u), callContext) <- SS.user
_ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext)
failMsg = s"$InvalidJsonFormat The Json body should be the $PutProductJsonV400 "
product <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.extract[PutProductJsonV500]
}
parentProductCode <- product.parent_product_code.trim.nonEmpty match {
case false =>
Future(Empty)
case true =>
Future(Connector.connector.vend.getProduct(bankId, ProductCode(product.parent_product_code))) map {
getFullBoxOrFail(_, callContext, ParentProductNotFoundByProductCode + " {" + product.parent_product_code + "}", 400)
}
}
success <- Future(Connector.connector.vend.createOrUpdateProduct(
bankId = bankId.value,
code = productCode.value,
parentProductCode = parentProductCode.map(_.code.value).toOption,
name = product.name,
category = null,
family = null,
superFamily = null,
moreInfoUrl = product.more_info_url.getOrElse(""),
termsAndConditionsUrl = product.terms_and_conditions_url.getOrElse(""),
details = null,
description = product.description.getOrElse(""),
metaLicenceId = product.meta.map(_.license.id).getOrElse(""),
metaLicenceName = product.meta.map(_.license.name).getOrElse("")
)) map {
connectorEmptyResponse(_, callContext)
}
} yield {
(JSONFactory400.createProductJson(success), HttpCode.`201`(callContext))
}
}
}
}
}

View File

@ -30,7 +30,7 @@ import java.util.Date
import code.api.util.APIUtil.stringOrNull
import code.api.v1_2_1.BankRoutingJsonV121
import code.api.v1_4_0.JSONFactory1_4_0.CustomerFaceImageJson
import code.api.v1_4_0.JSONFactory1_4_0.{CustomerFaceImageJson, MetaJsonV140}
import code.api.v2_1_0.CustomerCreditRatingJSON
import code.api.v3_1_0.PostConsentEntitlementJsonV310
import code.api.v4_0_0.BankAttributeBankResponseJsonV400
@ -80,6 +80,15 @@ case class PostCustomerJsonV500(
name_suffix: Option[String] = None
)
case class PutProductJsonV500(
parent_product_code: String,
name: String,
more_info_url: Option[String] = None,
terms_and_conditions_url: Option[String] = None,
description: Option[String] = None,
meta: Option[MetaJsonV140] = None,
)
case class UserAuthContextJsonV500(
user_auth_context_id: String,
user_id: String,

View File

@ -0,0 +1,169 @@
/**
Open Bank Project - API
Copyright (C) 2011-2019, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
*/
package code.api.v5_0_0
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.ApiRole._
import code.api.util.APIUtil.OAuth._
import code.api.util.ErrorMessages._
import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
import code.api.v4_0_0.{ProductJsonV400, ProductsJsonV400}
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
import scala.collection.immutable.Nil
class ProductTest extends V500ServerSetup {
override def beforeAll(): Unit = {
super.beforeAll()
}
override def afterAll(): Unit = {
super.afterAll()
}
/**
* Test tags
* Example: To run tests with tag "getPermissions":
* mvn test -D tagsToInclude
*
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations5_0_0.createProduct))
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.getProduct))
object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.getProducts))
lazy val testBankId = randomBankId
lazy val parentPutProductJsonV500: PutProductJsonV500 = SwaggerDefinitionsJSON.putProductJsonV500.copy(parent_product_code ="")
def createProduct(code: String, json: PutProductJsonV500): ProductJsonV400 = {
When("We try to create a product v4.0.0")
val request500 = (v5_0_0_Request / "banks" / testBankId / "products" / code).PUT <@ (user1)
val response500 = makePutRequest(request500, write(json))
Then("We should get a 201")
response500.code should equal(201)
val product = response500.body.extract[ProductJsonV400]
product.product_code shouldBe code
product.parent_product_code shouldBe json.parent_product_code
product.bank_id shouldBe testBankId
product.name shouldBe json.name
product.more_info_url shouldBe json.more_info_url.getOrElse("")
product.terms_and_conditions_url shouldBe json.terms_and_conditions_url.getOrElse("")
product.description shouldBe json.description.getOrElse("")
product
}
feature("Create Product v4.0.0") {
scenario("We will call the Add endpoint without a user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v5_0_0_Request / "banks" / testBankId / "products" / "CODE").PUT
val response400 = makePutRequest(request400, write(parentPutProductJsonV500))
Then("We should get a 401")
response400.code should equal(401)
And("error should be " + UserNotLoggedIn)
response400.body.extract[ErrorMessage].message should equal (UserNotLoggedIn)
}
scenario("We will call the Add endpoint without a proper role", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request500 = (v5_0_0_Request / "banks" / testBankId / "products" / "CODE").PUT <@(user1)
val response500 = makePutRequest(request500, write(parentPutProductJsonV500))
Then("We should get a 403")
response500.code should equal(403)
val createProductEntitlements = canCreateProduct :: canCreateProductAtAnyBank :: Nil
val createProductEntitlementsRequiredText = UserHasMissingRoles + createProductEntitlements.mkString(" or ")
And("error should be " + createProductEntitlementsRequiredText)
response500.body.extract[ErrorMessage].message contains (createProductEntitlementsRequiredText) should be (true)
}
scenario("We will call the Add endpoint with user credentials and role", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement(testBankId, resourceUser1.userId, CanCreateProduct.toString)
// Create an grandparent
val grandparent: ProductJsonV400 = createProduct(code = "GRANDPARENT_CODE", json = parentPutProductJsonV500)
// Create an parent
val product: ProductJsonV400 = createProduct(code = "PARENT_CODE", json = parentPutProductJsonV500.copy(parent_product_code = grandparent.product_code))
// Get
val requestGet400 = (v5_0_0_Request / "banks" / product.bank_id / "products" / product.product_code ).GET <@(user1)
val responseGet400 = makeGetRequest(requestGet400)
Then("We should get a 200")
responseGet400.code should equal(200)
val product1 = responseGet400.body.extract[ProductJsonV400]
// Create an child
val childPutProductJsonV400 = parentPutProductJsonV500.copy(parent_product_code = product.product_code)
createProduct(code = "PRODUCT_CODE", json = childPutProductJsonV400)
// Get
val requestGetAll400 = (v5_0_0_Request / "banks" / product.bank_id / "products").GET <@(user1)
val responseGetAll400 = makeGetRequest(requestGetAll400)
Then("We should get a 200")
responseGetAll400.code should equal(200)
val products: ProductsJsonV400 = responseGetAll400.body.extract[ProductsJsonV400]
products.products.size shouldBe 3
}
scenario("We will call the Add endpoint with user credentials and role and minimal PUT JSON", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement(testBankId, resourceUser1.userId, CanCreateProduct.toString)
// Create an grandparent
val grandparent: ProductJsonV400 = createProduct(
code = "GRANDPARENT_CODE",
json = PutProductJsonV500(
name = parentPutProductJsonV500.name,
parent_product_code = parentPutProductJsonV500.parent_product_code
)
)
// Create an parent
val product: ProductJsonV400 = createProduct(code = "PARENT_CODE", json = parentPutProductJsonV500.copy(parent_product_code = grandparent.product_code))
// Get
val requestGet400 = (v5_0_0_Request / "banks" / product.bank_id / "products" / product.product_code ).GET <@(user1)
val responseGet400 = makeGetRequest(requestGet400)
Then("We should get a 200")
responseGet400.code should equal(200)
val product1 = responseGet400.body.extract[ProductJsonV400]
// Create an child
val childPutProductJsonV400 = parentPutProductJsonV500.copy(parent_product_code = product.product_code)
createProduct(code = "PRODUCT_CODE", json = childPutProductJsonV400)
// Get
val requestGetAll400 = (v5_0_0_Request / "banks" / product.bank_id / "products").GET <@(user1)
val responseGetAll400 = makeGetRequest(requestGetAll400)
Then("We should get a 200")
responseGetAll400.code should equal(200)
val products: ProductsJsonV400 = responseGetAll400.body.extract[ProductsJsonV400]
products.products.size shouldBe 3
}
}
}

View File

@ -0,0 +1,27 @@
package code.api.v5_0_0
import code.api.v4_0_0.BanksJson400
import code.setup.{APIResponse, DefaultUsers, ServerSetupWithTestData}
import com.openbankproject.commons.util.ApiShortVersions
import dispatch.Req
import scala.util.Random.nextInt
trait V500ServerSetup extends ServerSetupWithTestData with DefaultUsers {
def v5_0_0_Request: Req = baseRequest / "obp" / "v5.0.0"
def dynamicEndpoint_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-endpoint`.toString
def dynamicEntity_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-entity`.toString
def randomBankId : String = {
def getBanksInfo : APIResponse = {
val request = v5_0_0_Request / "banks"
makeGetRequest(request)
}
val banksJson = getBanksInfo.body.extract[BanksJson400]
val randomPosition = nextInt(banksJson.banks.size)
val bank = banksJson.banks(randomPosition)
bank.id
}
}