feature/OBPv500 added new endpoints for customers

This commit is contained in:
hongwei 2022-09-09 13:34:51 +02:00
parent bbb0cb9b86
commit faaf2da5bf
6 changed files with 385 additions and 10 deletions

View File

@ -88,6 +88,12 @@ object ApiRole {
case class CanGetCustomersMinimalAtAnyBank(requiresBankId: Boolean = false) extends ApiRole
lazy val canGetCustomersMinimalAtAnyBank = CanGetCustomersMinimalAtAnyBank()
case class CanGetCustomers(requiresBankId: Boolean = true) extends ApiRole
lazy val canGetCustomers = CanGetCustomers()
case class CanGetCustomersMinimal(requiresBankId: Boolean = true) extends ApiRole
lazy val canGetCustomersMinimal = CanGetCustomersMinimal()
case class CanGetCustomer(requiresBankId: Boolean = true) extends ApiRole
lazy val canGetCustomer = CanGetCustomer()

View File

@ -5144,7 +5144,7 @@ trait APIMethods400 {
implementedInApiVersion,
nameOf(getCustomersMinimalAtAnyBank),
"GET",
"/customers/minimal",
"/customers-minimal",
"Get Customers Minimal at Any Bank",
s"""Get Customers Minimal at Any Bank.
|
@ -5163,7 +5163,7 @@ trait APIMethods400 {
Some(List(canGetCustomersMinimalAtAnyBank))
)
lazy val getCustomersMinimalAtAnyBank : OBPEndpoint = {
case "customers" :: "minimal" :: Nil JsonGet _ => {
case "customers-minimal" :: Nil JsonGet _ => {
cc => {
for {
requestParams <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)

View File

@ -2,12 +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, canGetUserAuthContext}
import code.api.util.ApiRole.{CanCreateUserAuthContextUpdate, 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.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.JSONFactory400.createCustomersMinimalJson
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
import code.entitlement.Entitlement
@ -19,11 +23,11 @@ import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.{BankId, UserAuthContextUpdateStatus}
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.common.{Full}
import net.liftweb.http.{Req}
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}
@ -615,6 +619,153 @@ trait APIMethods500 {
}
}
staticResourceDocs += ResourceDoc(
getMyCustomersAtAnyBank,
implementedInApiVersion,
nameOf(getMyCustomersAtAnyBank),
"GET",
"/my/customers",
"Get My Customers",
"""Gets all Customers that are linked to me.
|
|Authentication via OAuth is required.""",
emptyObjectJson,
customerJsonV210,
List(
$UserNotLoggedIn,
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagUser))
lazy val getMyCustomersAtAnyBank : OBPEndpoint = {
case "my" :: "customers" :: Nil JsonGet _ => {
cc => {
for {
(Full(u), callContext) <- SS.user
(customers, callContext) <- Connector.connector.vend.getCustomersByUserId(u.userId, callContext) map {
connectorEmptyResponse(_, callContext)
}
} yield {
(JSONFactory210.createCustomersJson(customers), HttpCode.`200`(callContext))
}
}
}
}
staticResourceDocs += ResourceDoc(
getMyCustomersAtBank,
implementedInApiVersion,
nameOf(getMyCustomersAtBank),
"GET",
"/banks/BANK_ID/my/customers",
"Get My Customers at Bank",
s"""Returns a list of Customers at the Bank that are linked to the currently authenticated User.
|
|
|${authenticationRequiredMessage(true)}""".stripMargin,
emptyObjectJson,
customerJSONs,
List(
$UserNotLoggedIn,
$BankNotFound,
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagNewStyle)
)
lazy val getMyCustomersAtBank : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "my" :: "customers" :: Nil JsonGet _ => {
cc => {
for {
(Full(u), callContext) <- SS.user
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
(customers, callContext) <- Connector.connector.vend.getCustomersByUserId(u.userId, callContext) map {
connectorEmptyResponse(_, callContext)
}
} yield {
// Filter so we only see the ones for the bank in question
val bankCustomers = customers.filter(_.bankId==bankId.value)
val json = JSONFactory210.createCustomersJson(bankCustomers)
(json, HttpCode.`200`(callContext))
}
}
}
}
staticResourceDocs += ResourceDoc(
getCustomersAtOneBank,
implementedInApiVersion,
nameOf(getCustomersAtOneBank),
"GET",
"/banks/BANK_ID/customers",
"Get Customers at Bank",
s"""Get Customers at Bank.
|
|
|${authenticationRequiredMessage(true)}
|
|""",
emptyObjectJson,
customersJsonV300,
List(
UserNotLoggedIn,
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagUser, apiTagNewStyle),
Some(List(canGetCustomers))
)
lazy val getCustomersAtOneBank : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet _ => {
cc => {
for {
requestParams <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
customers <- NewStyle.function.getCustomers(bankId, cc.callContext, requestParams)
} yield {
(JSONFactory300.createCustomersJson(customers.sortBy(_.bankId)), HttpCode.`200`(cc.callContext))
}
}
}
}
staticResourceDocs += ResourceDoc(
getCustomersMinimalAtOneBank,
implementedInApiVersion,
nameOf(getCustomersMinimalAtOneBank),
"GET",
"/banks/BANK_ID/customers-minimal",
"Get Customers Minimal at Bank",
s"""Get Customers Minimal at Bank.
|
|
|
|""",
emptyObjectJson,
customersMinimalJsonV300,
List(
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagUser, apiTagNewStyle),
Some(List(canGetCustomersMinimal))
)
lazy val getCustomersMinimalAtOneBank : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "customers-minimal" :: Nil JsonGet _ => {
cc => {
for {
requestParams <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
customers <- NewStyle.function.getCustomers(bankId, cc.callContext, requestParams)
} yield {
(createCustomersMinimalJson(customers.sortBy(_.bankId)), HttpCode.`200`(cc.callContext))
}
}
}
}
}
}

View File

@ -3491,7 +3491,9 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
override def getCustomers(bankId: BankId, callContext: Option[CallContext], queryParams: List[OBPQueryParam]): Future[Box[List[Customer]]] =
CustomerX.customerProvider.vend.getCustomersFuture(bankId, queryParams)
CustomerX.customerProvider.vend.getCustomersFuture(bankId, queryParams)map {
(_, callContext)
}
override def getCustomersByCustomerPhoneNumber(bankId: BankId, phoneNumber: String, callContext: Option[CallContext]): OBPReturnType[Box[List[Customer]]] =
CustomerX.customerProvider.vend.getCustomersByCustomerPhoneNumber(bankId, phoneNumber) map {

View File

@ -109,7 +109,7 @@ class CustomerTest extends V400ServerSetup with PropsReset{
feature(s"Get Customers Minimal at Any Bank $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint2, VersionOfApi) {
When(s"We make a request $VersionOfApi")
val request = (v4_0_0_Request / "customers" / "minimal").GET
val request = (v4_0_0_Request / "customers-minimal").GET
val response = makeGetRequest(request)
Then("We should get a 401")
response.code should equal(401)
@ -120,7 +120,7 @@ class CustomerTest extends V400ServerSetup with PropsReset{
feature(s"Get Customers Minimal at Any Bank $VersionOfApi - Authorized access") {
scenario("We will call the endpoint with user credentials", ApiEndpoint2, VersionOfApi) {
When(s"We make a request $VersionOfApi")
val request = (v4_0_0_Request / "customers" / "minimal").GET<@(user1)
val request = (v4_0_0_Request / "customers-minimal").GET<@(user1)
val response = makeGetRequest(request)
Then("We should get a 403")
response.code should equal(403)
@ -133,7 +133,7 @@ class CustomerTest extends V400ServerSetup with PropsReset{
scenario("We will call the endpoint with a user credentials and a proper role", ApiEndpoint1, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canGetCustomersMinimalAtAnyBank.toString)
When(s"We make a request $VersionOfApi")
val request = (v4_0_0_Request / "customers" / "minimal").GET <@(user1)
val request = (v4_0_0_Request / "customers-minimal").GET <@(user1)
val response = makeGetRequest(request)
Then("We should get a 200")
response.code should equal(200)

View File

@ -0,0 +1,216 @@
/**
Open Bank Project - API
Copyright (C) 2011-2022, 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.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{postUserAuthContextJson, postUserAuthContextUpdateJsonV310}
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v2_1_0.CustomerJSONs
import code.api.v3_0_0.CustomerJSONsV300
import code.api.v3_1_0.CustomerJsonV310
import code.api.v4_0_0.CustomersMinimalJsonV400
import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
import code.customer.CustomerX
import code.entitlement.Entitlement
import code.usercustomerlinks.UserCustomerLink
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 java.util.Date
import scala.language.postfixOps
class CustomerTest extends V500ServerSetupAsync {
override def beforeAll(): Unit = {
super.beforeAll()
}
override def afterAll(): Unit = {
super.afterAll()
CustomerX.customerProvider.vend.bulkDeleteCustomers()
UserCustomerLink.userCustomerLink.vend.bulkDeleteUserCustomerLinks()
}
/**
* 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.getMyCustomersAtAnyBank))
object ApiEndpoint2 extends Tag(nameOf(Implementations5_0_0.getMyCustomersAtBank))
object ApiEndpoint3 extends Tag(nameOf(Implementations5_0_0.getCustomersAtOneBank))
object ApiEndpoint4 extends Tag(nameOf(Implementations5_0_0.getCustomersMinimalAtOneBank))
lazy val bankId = testBankId1.value
val postCustomerJson = SwaggerDefinitionsJSON.postCustomerJsonV310.copy(last_ok_date= new Date())
feature(s"$ApiEndpoint1 $ApiEndpoint2 $ApiEndpoint3 $ApiEndpoint4 successful cases") {
scenario(s"We will call $ApiEndpoint1 with credentials", ApiEndpoint1, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanCreateCustomer.toString)
When("we prepare the user1's customer")
val postRequestCreateCustomer = (v5_0_0_Request / "banks" / bankId / "customers").POST <@(user1)
val postResponseCreateCustomer = makePostRequest(postRequestCreateCustomer, write(postCustomerJson))
Then("We should get a 201")
postResponseCreateCustomer.code should equal(201)
val customerIdUser1 = postResponseCreateCustomer.body.extract[CustomerJsonV310].customer_id
lazy val createUserCustomerLinkJson = SwaggerDefinitionsJSON.createUserCustomerLinkJson
.copy(user_id = resourceUser1.userId, customer_id = customerIdUser1)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanCreateUserCustomerLink.toString())
val createRequestCustomerLinkUser1 = (v5_0_0_Request / "banks" / bankId / "user_customer_links" ).POST <@(user1)
val createResponseCustomerLinkUser1 = makePostRequest(createRequestCustomerLinkUser1, write(createUserCustomerLinkJson))
Then("We should get a 201")
createResponseCustomerLinkUser1.code should equal(201)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser2.userId, CanCreateCustomer.toString)
Then("we prepare the user2's customer")
val postRequestCreateCustomerUser2 = (v5_0_0_Request / "banks" / bankId / "customers").POST <@(user2)
val postResponseCreateCustomerUser2 = makePostRequest(postRequestCreateCustomerUser2, write(postCustomerJson))
Then("We should get a 201")
postResponseCreateCustomerUser2.code should equal(201)
val customerIdUser2 = postResponseCreateCustomerUser2.body.extract[CustomerJsonV310].customer_id
lazy val createUserCustomerLinkJsonUser2 = SwaggerDefinitionsJSON.createUserCustomerLinkJson
.copy(user_id = resourceUser2.userId, customer_id = customerIdUser2)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser2.userId, CanCreateUserCustomerLink.toString())
val createRequest = (v5_0_0_Request / "banks" / bankId / "user_customer_links" ).POST <@(user1)
val createResponse = makePostRequest(createRequest, write(createUserCustomerLinkJsonUser2))
Then("We should get a 201")
createResponse.code should equal(201)
Then(s"We test $ApiEndpoint1")
val requestApiEndpoint1 = (v5_0_0_Request / "my"/ "customers").GET <@(user1)
val responseApiEndpoint1 = makeGetRequest(requestApiEndpoint1)
Then("We should get a 200")
responseApiEndpoint1.code should equal(200)
responseApiEndpoint1.body.extract[CustomerJSONs].customers.length == 1 should be (true)
Then(s"We test $ApiEndpoint2")
val requestApiEndpoint2 = (v5_0_0_Request / "banks"/ bankId /"my"/ "customers").GET <@(user1)
val responseApiEndpoint2 = makeGetRequest(requestApiEndpoint2)
Then("We should get a 200")
responseApiEndpoint2.code should equal(200)
responseApiEndpoint2.body.extract[CustomerJSONs].customers.length == 1 should be (true)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanGetCustomers.toString)
Then(s"We test $ApiEndpoint3")
val requestApiEndpoint3 = (v5_0_0_Request / "banks"/ bankId /"customers").GET <@(user1)
val responseApiEndpoint3 = makeGetRequest(requestApiEndpoint3)
Then("We should get a 200")
responseApiEndpoint3.code should equal(200)
responseApiEndpoint3.body.extract[CustomerJSONsV300].customers.length == 2 should be (true)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanGetCustomersMinimal.toString)
Then(s"We test $ApiEndpoint4")
val requestApiEndpoint4 = (v5_0_0_Request / "banks"/ bankId /"customers-minimal").GET <@(user1)
val responseApiEndpoint4 = makeGetRequest(requestApiEndpoint4)
Then("We should get a 200")
responseApiEndpoint4.code should equal(200)
responseApiEndpoint4.body.extract[CustomersMinimalJsonV400].customers.length == 2 should be (true)
}
}
feature(s"$ApiEndpoint1 $ApiEndpoint2 $ApiEndpoint3 $ApiEndpoint4 error cases") {
scenario(s"$ApiEndpoint1 without a user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint1 = (v5_0_0_Request / "my"/ "customers").GET
val responseApiEndpoint1 = makeGetRequest(requestApiEndpoint1)
Then("We should get a 401")
responseApiEndpoint1.code should equal(401)
And("error should be " + UserNotLoggedIn)
responseApiEndpoint1.body.extract[ErrorMessage].message should equal (UserNotLoggedIn)
}
scenario(s"$ApiEndpoint2 without a user credentials", ApiEndpoint2, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint2 = (v5_0_0_Request / "my"/ "customers").GET
val responseApiEndpoint2 = makeGetRequest(requestApiEndpoint2)
Then("We should get a 401")
responseApiEndpoint2.code should equal(401)
And("error should be " + UserNotLoggedIn)
responseApiEndpoint2.body.extract[ErrorMessage].message should equal (UserNotLoggedIn)
}
scenario(s"$ApiEndpoint3 without a user credentials", ApiEndpoint3, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint3 = (v5_0_0_Request / "banks"/ bankId /"customers").GET
val responseApiEndpoint3 = makeGetRequest(requestApiEndpoint3)
Then("We should get a 401")
responseApiEndpoint3.code should equal(401)
And("error should be " + UserNotLoggedIn)
responseApiEndpoint3.body.extract[ErrorMessage].message should equal (UserNotLoggedIn)
}
scenario(s"$ApiEndpoint3 miss role", ApiEndpoint3, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint3 = (v5_0_0_Request / "banks"/ bankId /"customers").GET <@(user1)
val responseApiEndpoint3 = makeGetRequest(requestApiEndpoint3)
Then("We should get a 403")
responseApiEndpoint3.code should equal(403)
And("error should be " + UserHasMissingRoles + CanGetUserAuthContext)
responseApiEndpoint3.body.extract[ErrorMessage].message contains (UserHasMissingRoles ) should be (true)
responseApiEndpoint3.body.extract[ErrorMessage].message contains (CanGetCustomers.toString()) should be (true)
}
scenario(s"$ApiEndpoint4 without a user credentials", ApiEndpoint4, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint4 = (v5_0_0_Request / "banks"/ bankId /"customers-minimal").GET
val responseApiEndpoint4 = makeGetRequest(requestApiEndpoint4)
Then("We should get a 401")
responseApiEndpoint4.code should equal(401)
And("error should be " + UserNotLoggedIn)
responseApiEndpoint4.body.extract[ErrorMessage].message should equal (UserNotLoggedIn)
}
scenario(s"$ApiEndpoint4 miss role", ApiEndpoint4, VersionOfApi) {
When("We make a request v5.0.0")
val requestApiEndpoint4 = (v5_0_0_Request / "banks"/ bankId /"customers-minimal").GET <@(user1)
val responseApiEndpoint4 = makeGetRequest(requestApiEndpoint4)
Then("We should get a 403")
responseApiEndpoint4.code should equal(403)
And("error should be " + UserHasMissingRoles + CanGetUserAuthContext)
responseApiEndpoint4.body.extract[ErrorMessage].message contains (UserHasMissingRoles ) should be (true)
responseApiEndpoint4.body.extract[ErrorMessage].message contains (CanGetCustomersMinimal.toString()) should be (true)
}
}
}