feature/Add endpoint getSystemView v5.0.0

This commit is contained in:
Marko Milić 2022-10-17 11:29:19 +02:00
parent 7a546769ee
commit e34303c8a2
3 changed files with 410 additions and 14 deletions

View File

@ -2735,6 +2735,99 @@ object SwaggerDefinitionsJSON {
views = List(viewJSONV220)
)
val viewJsonV500 = ViewJsonV500(
id = "1234",
short_name = "short_name",
description = "description",
metadata_view = SYSTEM_OWNER_VIEW_ID,
is_public = true,
is_system = true,
alias = "No",
hide_metadata_if_alias_used = true,
can_add_comment = true,
can_add_corporate_location = true,
can_add_image = true,
can_add_image_url = true,
can_add_more_info = true,
can_add_open_corporates_url = true,
can_add_physical_location = true,
can_add_private_alias = true,
can_add_public_alias = true,
can_add_tag = true,
can_add_url = true,
can_add_where_tag = true,
can_delete_comment = true,
can_add_counterparty = true,
can_delete_corporate_location = true,
can_delete_image = true,
can_delete_physical_location = true,
can_delete_tag = true,
can_delete_where_tag = true,
can_edit_owner_comment = true,
can_see_bank_account_balance = true,
can_query_available_funds = true,
can_see_bank_account_bank_name = true,
can_see_bank_account_currency = true,
can_see_bank_account_iban = true,
can_see_bank_account_label = true,
can_see_bank_account_national_identifier = true,
can_see_bank_account_number = true,
can_see_bank_account_owners = true,
can_see_bank_account_swift_bic = true,
can_see_bank_account_type = true,
can_see_comments = true,
can_see_corporate_location = true,
can_see_image_url = true,
can_see_images = true,
can_see_more_info = true,
can_see_open_corporates_url = true,
can_see_other_account_bank_name = true,
can_see_other_account_iban = true,
can_see_other_account_kind = true,
can_see_other_account_metadata = true,
can_see_other_account_national_identifier = true,
can_see_other_account_number = true,
can_see_other_account_swift_bic = true,
can_see_owner_comment = true,
can_see_physical_location = true,
can_see_private_alias = true,
can_see_public_alias = true,
can_see_tags = true,
can_see_transaction_amount = true,
can_see_transaction_balance = true,
can_see_transaction_currency = true,
can_see_transaction_description = true,
can_see_transaction_finish_date = true,
can_see_transaction_metadata = true,
can_see_transaction_other_bank_account = true,
can_see_transaction_start_date = true,
can_see_transaction_this_bank_account = true,
can_see_transaction_type = true,
can_see_url = true,
can_see_where_tag = true,
//V300 new
can_see_bank_routing_scheme = true,
can_see_bank_routing_address = true,
can_see_bank_account_routing_scheme = true,
can_see_bank_account_routing_address = true,
can_see_other_bank_routing_scheme = true,
can_see_other_bank_routing_address = true,
can_see_other_account_routing_scheme = true,
can_see_other_account_routing_address = true,
can_add_transaction_request_to_own_account = true, //added following two for payments
can_add_transaction_request_to_any_account = true,
can_see_bank_account_credit_limit = true,
can_create_direct_debit = true,
can_create_standing_order = true,
can_grant_access_to_views = List("Owner"),
can_revoke_access_to_views = List("Owner")
)
val viewsJsonV500 = ViewsJsonV500(
views = List(viewJsonV500)
)
val fXRateJSON = FXRateJsonV220(
bank_id = bankIdExample.value,
from_currency_code = "EUR",

View File

@ -1,7 +1,8 @@
package code.api.v5_0_0
import java.util.Date
import java.util.concurrent.ThreadLocalRandom
import code.accountattribute.AccountAttributeX
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil._
import code.api.util.ApiRole._
@ -15,36 +16,30 @@ 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.api.v5_0_0.JSONFactory500.createPhysicalCardJson
import code.api.v5_0_0.JSONFactory500.{createPhysicalCardJson, createViewsJsonV500, createViewJsonV500}
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
import code.model._
import code.entitlement.Entitlement
import code.model._
import code.model.dataAccess.BankAccountCreation
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
import code.util.Helper
import code.util.Helper.booleanToFuture
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.{AccountAttribute, AccountId, AccountRouting, BankAccount, BankId, BankIdAccountId, CardAction, CardAttributeCommons, CardCollectionInfo, CardPostedInfo, CardReplacementInfo, CardReplacementReason, CreditLimit, CreditRating, CustomerFaceImage, CustomerId, PinResetInfo, PinResetReason, ProductCode, TransactionRequestType, UserAuthContextUpdateStatus, View, ViewId}
import com.openbankproject.commons.model._
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.common.{Empty, Full}
import net.liftweb.http.Req
import net.liftweb.http.rest.RestHelper
import net.liftweb.json
import net.liftweb.json.{Extraction, compactRender, prettyRender}
import net.liftweb.util.Helpers.tryo
import net.liftweb.util.Props
import java.util.concurrent.ThreadLocalRandom
import code.accountattribute.AccountAttributeX
import code.api.v5_0_0.JSONFactory500.createViewsJsonV500
import code.util.Helper.booleanToFuture
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import scala.concurrent
import scala.concurrent.Future
import scala.util.Random
@ -1447,7 +1442,7 @@ trait APIMethods500 {
}
resourceDocs += ResourceDoc(
staticResourceDocs += ResourceDoc(
getViewsForBankAccount,
implementedInApiVersion,
nameOf(getViewsForBankAccount),
@ -1479,7 +1474,7 @@ trait APIMethods500 {
|
|${authenticationRequiredMessage(true)} and the user needs to have access to the owner view.""",
emptyObjectJson,
viewsJsonV300,
viewsJsonV500,
List(
$UserNotLoggedIn,
$BankAccountNotFound,
@ -1507,6 +1502,41 @@ trait APIMethods500 {
}
}
staticResourceDocs += ResourceDoc(
getSystemView,
implementedInApiVersion,
"getSystemView",
"GET",
"/system-views/VIEW_ID",
"Get System View",
s"""Get System View
|
|${authenticationRequiredMessage(true)}
|
""".stripMargin,
emptyObjectJson,
viewJsonV500,
List(
$UserNotLoggedIn,
$BankNotFound,
UnknownError
),
List(apiTagSystemView, apiTagNewStyle),
Some(List(canGetSystemView))
)
lazy val getSystemView: OBPEndpoint = {
case "system-views" :: viewId :: Nil JsonGet _ => {
cc =>
for {
view <- NewStyle.function.systemView(ViewId(viewId), cc.callContext)
} yield {
(createViewJsonV500(view), HttpCode.`200`(cc.callContext))
}
}
}
staticResourceDocs += ResourceDoc(
createCustomerAccountLink,
implementedInApiVersion,

View File

@ -0,0 +1,273 @@
/**
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.
Osloer Strasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
*/
package code.api.v5_0_0
import _root_.net.liftweb.json.Serialization.write
import code.api.Constant._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole.{CanCreateSystemView, CanDeleteSystemView, CanGetSystemView, CanUpdateSystemView}
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
import code.api.v3_0_0.ViewJsonV300
import code.api.v3_1_0.APIMethods310.Implementations3_1_0
import code.api.v5_0_0.APIMethods500.Implementations5_0_0
import code.entitlement.Entitlement
import code.setup.APIResponse
import code.views.MapperViews
import code.views.system.AccountAccess
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{CreateViewJson, ErrorMessage, UpdateViewJSON}
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.mapper.By
import org.scalatest.Tag
class SystemViewsTests 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.getSystemView))
object ApiEndpoint2 extends Tag(nameOf(Implementations3_1_0.createSystemView))
object ApiEndpoint3 extends Tag(nameOf(Implementations3_1_0.updateSystemView))
object ApiEndpoint4 extends Tag(nameOf(Implementations3_1_0.deleteSystemView))
// Custom view, name starts from `_`
// System view, owner
val randomSystemViewId = APIUtil.generateUUID()
val postBodySystemViewJson = createSystemViewJson.copy(name=randomSystemViewId).copy(metadata_view = randomSystemViewId)
val systemViewId = MapperViews.getNewViewPermalink(postBodySystemViewJson.name)
def getSystemView(viewId : String, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
val request = v5_0_0_Request / "system-views" / viewId <@(consumerAndToken)
makeGetRequest(request)
}
def postSystemView(view: CreateViewJson, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
val request = (v5_0_0_Request / "system-views").POST <@(consumerAndToken)
makePostRequest(request, write(view))
}
def putSystemView(viewId : String, view: UpdateViewJSON, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
val request = (v5_0_0_Request / "system-views" / viewId).PUT <@(consumerAndToken)
makePutRequest(request, write(view))
}
def deleteSystemView(viewId : String, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
val request = (v5_0_0_Request / "system-views" / viewId).DELETE <@(consumerAndToken)
makeDeleteRequest(request)
}
def createSystemView(viewId: String): Boolean = {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemView.toString)
val postBody = postBodySystemViewJson.copy(name=viewId).copy(metadata_view = viewId)
val response400 = postSystemView(postBody, user1)
response400.code == 201
}
feature(s"test $ApiEndpoint2 version $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When(s"We make a request $ApiEndpoint2")
val response400 = postSystemView(postBodySystemViewJson, None)
Then("We should get a 401")
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
}
feature(s"test $ApiEndpoint2 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When(s"We make a request $ApiEndpoint2")
val response400 = postSystemView(postBodySystemViewJson, user1)
Then("We should get a 403")
response400.code should equal(403)
response400.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanCreateSystemView)
}
}
feature(s"test $ApiEndpoint2 version $VersionOfApi - Authorized access with proper Role") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When(s"We make a request $ApiEndpoint2")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemView.toString)
val response400 = postSystemView(postBodySystemViewJson, user1)
Then("We should get a 201")
response400.code should equal(201)
response400.body.extract[ViewJsonV300]
}
}
feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When(s"We make a request $ApiEndpoint1")
val response400 = getSystemView("", None)
Then("We should get a 401")
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
}
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When(s"We make a request $ApiEndpoint1")
val response400 = getSystemView("", user1)
Then("We should get a 403")
response400.code should equal(403)
response400.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanGetSystemView)
}
}
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access with proper Role") {
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
val viewId = APIUtil.generateUUID()
createSystemView(viewId)
When(s"We make a request $ApiEndpoint1")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetSystemView.toString)
val response400 = getSystemView(viewId, user1)
Then("We should get a 200")
response400.code should equal(200)
response400.body.extract[ViewJsonV500]
}
}
feature(s"test $ApiEndpoint3 version $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint3, VersionOfApi) {
When(s"We make a request $ApiEndpoint3")
val response400 = getSystemView("", None)
Then("We should get a 401")
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
}
feature(s"test $ApiEndpoint3 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint3, VersionOfApi) {
When(s"We make a request $ApiEndpoint3")
val response400 = getSystemView("", user1)
Then("We should get a 403")
response400.code should equal(403)
response400.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanGetSystemView)
}
}
feature(s"test $ApiEndpoint3 version $VersionOfApi - Authorized access with proper Role") {
scenario("we will update a view on a bank account", ApiEndpoint3, VersionOfApi) {
val updatedViewDescription = "aloha"
val updatedAliasToUse = "public"
val allowedActions = List("can_see_images", "can_delete_comment")
def viewUpdateJson(originalView : ViewJsonV300) = {
//it's not perfect, assumes too much about originalView (i.e. randomView(true, ""))
UpdateViewJSON(
description = updatedViewDescription,
metadata_view = originalView.metadata_view,
is_public = originalView.is_public,
is_firehose = Some(true),
which_alias_to_use = updatedAliasToUse,
hide_metadata_if_alias_used = !originalView.hide_metadata_if_alias_used,
allowed_actions = allowedActions
)
}
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemView.toString)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanUpdateSystemView.toString)
Given("A view exists")
val creationReply = postSystemView(postBodySystemViewJson, user1)
creationReply.code should equal (201)
val createdView : ViewJsonV300 = creationReply.body.extract[ViewJsonV300]
createdView.id should not startWith("_")
createdView.can_see_images should equal(true)
createdView.can_delete_comment should equal(true)
createdView.can_delete_physical_location should equal(true)
createdView.can_edit_owner_comment should equal(true)
createdView.description should not equal(updatedViewDescription)
createdView.hide_metadata_if_alias_used should equal(false)
When("We use a valid access token and valid put json")
val reply = putSystemView(createdView.id, viewUpdateJson(createdView), user1)
Then("We should get back the updated view")
reply.code should equal (200)
val updatedView = reply.body.extract[ViewJsonV300]
updatedView.can_see_images should equal(true)
updatedView.can_delete_comment should equal(true)
updatedView.can_delete_physical_location should equal(false)
updatedView.can_edit_owner_comment should equal(false)
updatedView.description should equal(updatedViewDescription)
updatedView.hide_metadata_if_alias_used should equal(true)
updatedView.is_firehose should equal(Some(true))
}
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
When(s"We make a request $ApiEndpoint4")
val response400 = deleteSystemView("", None)
Then("We should get a 401")
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
When(s"We make a request $ApiEndpoint4")
val response400 = deleteSystemView("", user1)
Then("We should get a 403")
response400.code should equal(403)
response400.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanDeleteSystemView)
}
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access with proper Role") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
val viewId = APIUtil.generateUUID()
createSystemView(viewId)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteSystemView.toString)
When(s"We make a request $ApiEndpoint4")
val response400 = deleteSystemView(viewId, user1)
Then("We should get a 200")
response400.code should equal(200)
}
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access with proper Role in order to delete owner view") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteSystemView.toString)
When(s"We make a request $ApiEndpoint4")
AccountAccess.findAll(
By(AccountAccess.view_id, SYSTEM_OWNER_VIEW_ID),
By(AccountAccess.user_fk, resourceUser1.id.get)
).forall(_.delete_!) // Remove all rows assigned to the system owner view in order to delete it
val response400 = deleteSystemView(SYSTEM_OWNER_VIEW_ID, user1)
Then("We should get a 200")
response400.code should equal(200)
}
}
}