diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala index abb60e052f..7cc8dbbb86 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala @@ -180,6 +180,8 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth case ApiVersion.v6_0_0 => resourceDocs // fully on http4s — no Lift route filter case ApiVersion.v5_1_0 => resourceDocs // fully on http4s — no Lift route filter case ApiVersion.v5_0_0 => resourceDocs // fully on http4s — no Lift route filter + case ApiVersion.v4_0_0 => resourceDocs // fully on http4s — no Lift route filter + case ApiVersion.v3_1_0 => resourceDocs // fully on http4s — no Lift route filter case _ => resourceDocs.filter(rd => versionRoutesClasses.contains(rd.partialFunction.getClass)) } 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 64ee5f1e84..aedc60c389 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,6065 +1,23 @@ package code.api.v3_1_0 -import scala.language.reflectiveCalls -import code.api.Constant -import code.api.Constant._ -import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._ -import code.api.ResourceDocs1_4_0.{MessageDocsSwaggerDefinitions, ResourceDocsAPIMethodsUtil, SwaggerDefinitionsJSON, SwaggerJSONFactory} -import code.api.cache.Caching -import code.api.util.APIUtil.{getWebUIPropsPairs, _} -import code.api.util.ApiRole._ -import code.api.util.ApiTag._ -import code.api.util.ErrorMessages.{BankAccountNotFound, _} -import code.api.util.ExampleValue._ -import code.api.util.Glossary -import code.api.util.FutureUtil.EndpointContext -import code.api.util.NewStyle.HttpCode -import code.api.util._ -import code.api.util.newstyle.{BalanceNewStyle, ViewNewStyle} -import code.api.v1_2_1.{JSONFactory, RateLimiting} -import code.api.v1_4_0.JSONFactory1_4_0 -import code.api.v2_0_0.CreateMeetingJson -import code.api.v2_1_0._ -import code.api.v3_0_0.JSONFactory300.createAdapterInfoJson -import code.api.v3_0_0.{CreateViewJsonV300, JSONFactory300} -import code.api.v3_1_0.JSONFactory310._ -import code.bankconnectors.rest.RestConnector_vMar2019 -import code.bankconnectors.{Connector, LocalMappedConnector} -import code.consent.{ConsentStatus, Consents, DoobieConsentQueries, MappedConsent} -import code.consumer.Consumers -import code.entitlement.Entitlement -import code.loginattempts.LoginAttempt -import code.methodrouting.{MethodRouting, MethodRoutingCommons, MethodRoutingParam} -import code.metrics.APIMetrics -import code.model._ -import code.model.dataAccess.{AuthUser, BankAccountCreation} -import code.ratelimiting.RateLimitingDI -import code.userlocks.UserLocksProvider -import code.users.Users -import code.util.Helper -import code.util.Helper.ObpS -import code.views.Views -import code.webhook.AccountWebhook -import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons} -import com.github.dwickern.macros.NameOf.nameOf -import com.openbankproject.commons.ExecutionContext.Implicits.global -import com.openbankproject.commons.dto.GetProductsParam -import com.openbankproject.commons.model._ -import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, ProductAttributeType, StrongCustomerAuthentication} -import com.openbankproject.commons.util.{ApiVersion, ReflectUtils} -import net.liftweb.common.{Box, Empty, Full} -import net.liftweb.http.provider.HTTPParam import net.liftweb.http.rest.RestHelper -import net.liftweb.json -import net.liftweb.json._ -import net.liftweb.mapper.By -import net.liftweb.util.Helpers.tryo -import net.liftweb.util.{Helpers, Props} -import org.apache.commons.lang3.{StringUtils, Validate} -import java.text.SimpleDateFormat -import java.util.UUID -import java.util.regex.Pattern -import scala.collection.immutable.{List, Nil} -import scala.collection.mutable.ArrayBuffer -import scala.concurrent.Future - -trait APIMethods310 { - self: RestHelper => - - val Implementations3_1_0 = new Implementations310() - // note, because RestHelper have a impicit Formats, it is not correct for OBP, so here override it - protected implicit override abstract def formats: Formats = CustomJsonFormats.formats - - class Implementations310 { - - val implementedInApiVersion = ApiVersion.v3_1_0 - - val resourceDocs = ArrayBuffer[ResourceDoc]() - val apiRelations = ArrayBuffer[ApiRelation]() - val codeContext = CodeContext(resourceDocs, apiRelations) - - - resourceDocs += ResourceDoc( - root, - implementedInApiVersion, - "root", - "GET", - "/root", - "Get API Info (root)", - """Returns information about: - | - |* API version - |* Hosted by information - |* Git Commit""", - EmptyBody, - apiInfoJSON, - List(UnknownError, MandatoryPropertyIsNotSet), - apiTagApi :: Nil) - - lazy val root : OBPEndpoint = { - case (Nil | "root" :: Nil) JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Future(()) // Just start async call - } yield { - (JSONFactory.getApiInfoJSON(OBPAPI3_1_0.version, OBPAPI3_1_0.versionStatus), HttpCode.`200`(cc.callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getCheckbookOrders, - implementedInApiVersion, - nameOf(getCheckbookOrders), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/checkbook/orders", - "Get Checkbook orders", - s"""${mockedDataText(false)}Get all checkbook orders""", - EmptyBody, - checkbookOrdersJson, - List( - AuthenticatedUserIsRequired, - BankNotFound, - BankAccountNotFound, - InvalidConnectorResponseForGetCheckbookOrdersFuture, - UnknownError - ), - apiTagAccount :: Nil) - - lazy val getCheckbookOrders : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "checkbook" :: "orders" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - - view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext) - - (checkbookOrders, callContext)<- Connector.connector.vend.getCheckbookOrders(bankId.value,accountId.value, callContext) map { - unboxFullOrFail(_, callContext, InvalidConnectorResponseForGetCheckbookOrdersFuture) - } - } yield - (JSONFactory310.createCheckbookOrdersJson(checkbookOrders), HttpCode.`200`(callContext)) - } - } - - resourceDocs += ResourceDoc( - getStatusOfCreditCardOrder, - implementedInApiVersion, - nameOf(getStatusOfCreditCardOrder), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/credit_cards/orders", - "Get status of Credit Card order ", - s"""${mockedDataText(false)}Get status of Credit Card orders - |Get all orders - |""", - EmptyBody, - creditCardOrderStatusResponseJson, - List( - AuthenticatedUserIsRequired, - BankNotFound, - BankAccountNotFound, - InvalidConnectorResponseForGetStatusOfCreditCardOrderFuture, - UnknownError - ), - apiTagCard :: Nil) - - lazy val getStatusOfCreditCardOrder : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "credit_cards" :: "orders" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - - view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext) - - //TODO need error handling here - (checkbookOrders,callContext) <- Connector.connector.vend.getStatusOfCreditCardOrder(bankId.value,accountId.value, callContext) map { - unboxFullOrFail(_, callContext, InvalidConnectorResponseForGetStatusOfCreditCardOrderFuture) - } - - } yield - (JSONFactory310.createStatisOfCreditCardJson(checkbookOrders), HttpCode.`200`(callContext)) - } - } - - resourceDocs += ResourceDoc( - getTopAPIs, - implementedInApiVersion, - nameOf(getTopAPIs), - "GET", - "/management/metrics/top-apis", - "Get Top APIs", - s"""Get metrics about the most popular APIs. e.g.: total count, response time (in ms), etc. - | - |Should be able to filter on the following fields - | - |eg: /management/metrics/top-apis?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5 - |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount - |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions - |&verb=GET&anon=false&app_name=MapperPostman - |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null - | - |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString - | - |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString - | - |3 consumer_id (if null ignore) - | - |4 user_id (if null ignore) - | - |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.) - | - |6 url (if null ignore), note: can not contain '&'. - | - |7 app_name (if null ignore) - | - |8 implemented_by_partial_function (if null ignore), - | - |9 implemented_in_version (if null ignore) - | - |10 verb (if null ignore) - | - |11 correlation_id (if null ignore) - | - |12 duration (if null ignore) non digit chars will be silently omitted - | - |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null - | - |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics% - | - |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - topApisJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidFilterParameterFormat, - GetTopApisError, - UnknownError - ), - apiTagMetric :: Nil, - Some(List(canReadMetrics)) - ) - - lazy val getTopAPIs : OBPEndpoint = { - case "management" :: "metrics" :: "top-apis" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - - (Full(u), callContext) <- authenticatedAccess(cc) - - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext) - - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - - (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext) - - toApis <- APIMetrics.apiMetrics.vend.getTopApisFuture(obpQueryParams) map { - unboxFullOrFail(_, callContext, GetTopApisError) - } - } yield - (JSONFactory310.createTopApisJson(toApis), HttpCode.`200`(callContext)) - } - } - - resourceDocs += ResourceDoc( - getMetricsTopConsumers, - implementedInApiVersion, - nameOf(getMetricsTopConsumers), - "GET", - "/management/metrics/top-consumers", - "Get Top Consumers", - s"""Get metrics about the top consumers of the API usage e.g. total count, consumer_id and app_name. - | - |Should be able to filter on the following fields - | - |e.g.: /management/metrics/top-consumers?from_date=$epochTimeString&to_date=$DefaultToDateString&consumer_id=5 - |&user_id=66214b8e-259e-44ad-8868-3eb47be70646&implemented_by_partial_function=getTransactionsForBankAccount - |&implemented_in_version=v3.0.0&url=/obp/v3.0.0/banks/gh.29.uk/accounts/8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0/owner/transactions - |&verb=GET&anon=false&app_name=MapperPostman - |&exclude_app_names=API-EXPLORER,API-Manager,SOFI,null - |&limit=100 - | - |1 from_date (defaults to the one year ago): eg:from_date=$epochTimeString - | - |2 to_date (defaults to the current date) eg:to_date=$DefaultToDateString - | - |3 consumer_id (if null ignore) - | - |4 user_id (if null ignore) - | - |5 anon (if null ignore) only support two value : true (return where user_id is null.) or false (return where user_id is not null.) - | - |6 url (if null ignore), note: can not contain '&'. - | - |7 app_name (if null ignore) - | - |8 implemented_by_partial_function (if null ignore), - | - |9 implemented_in_version (if null ignore) - | - |10 verb (if null ignore) - | - |11 correlation_id (if null ignore) - | - |12 duration (if null ignore) non digit chars will be silently omitted - | - |13 exclude_app_names (if null ignore).eg: &exclude_app_names=API-EXPLORER,API-Manager,SOFI,null - | - |14 exclude_url_patterns (if null ignore).you can design you own SQL NOT LIKE pattern. eg: &exclude_url_patterns=%management/metrics%,%management/aggregate-metrics% - | - |15 exclude_implemented_by_partial_functions (if null ignore).eg: &exclude_implemented_by_partial_functions=getMetrics,getConnectorMetrics,getAggregateMetrics - | - |16 limit (for pagination: defaults to 50) eg:limit=200 - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - topConsumersJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidFilterParameterFormat, - GetMetricsTopConsumersError, - UnknownError - ), - apiTagMetric :: Nil, - Some(List(canReadMetrics)) - ) - - lazy val getMetricsTopConsumers : OBPEndpoint = { - case "management" :: "metrics" :: "top-consumers" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - - (Full(u), callContext) <- authenticatedAccess(cc) - - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadMetrics, callContext) - - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - - (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext) - - topConsumers <- APIMetrics.apiMetrics.vend.getTopConsumersFuture(obpQueryParams) map { - unboxFullOrFail(_, callContext, GetMetricsTopConsumersError) - } - - } yield - (JSONFactory310.createTopConsumersJson(topConsumers), HttpCode.`200`(callContext)) - } - } - - - - - - - - - - - resourceDocs += ResourceDoc( - getFirehoseCustomers, - implementedInApiVersion, - nameOf(getFirehoseCustomers), - "GET", - "/banks/BANK_ID/firehose/customers", - "Get Firehose Customers", - s""" - |Get Customers that has a firehose View. - | - |Allows bulk access to customers. - |User must have the CanUseFirehoseAtAnyBank Role - | - |${urlParametersDocument(true, true)} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - customerJSONs, - List(AuthenticatedUserIsRequired, CustomerFirehoseNotAllowedOnThisInstance, UserHasMissingRoles, UnknownError), - List(apiTagCustomer, apiTagFirehoseData), - Some(List(ApiRole.canUseCustomerFirehose, canUseCustomerFirehoseAtAnyBank))) - - lazy val getFirehoseCustomers : OBPEndpoint = { - //get private accounts for all banks - case "banks" :: BankId(bankId):: "firehose" :: "customers" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- Helper.booleanToFuture(failMsg = AccountFirehoseNotAllowedOnThisInstance , cc=callContext) { - allowCustomerFirehose - } - _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, ApiRole.canUseCustomerFirehose :: canUseCustomerFirehoseAtAnyBank :: Nil, callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - allowedParams = List("sort_direction", "limit", "offset", "from_date", "to_date") - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - (obpQueryParams, callContext) <- NewStyle.function.createObpParams(httpParams, allowedParams, callContext) - customers <- NewStyle.function.getCustomers(bankId, callContext, obpQueryParams) - reqParams = req.params.filterNot(param => allowedParams.contains(param._1)) - (customersFiltered, callContext) <- if(reqParams.isEmpty) { - Future {(customers, callContext)} - } else { - for{ - (customerIds, callContext) <- NewStyle.function.getCustomerIdsByAttributeNameValues(bankId, reqParams, callContext) - }yield{ - (customers.filter(customer => customerIds.contains(CustomerId(customer.customerId))),callContext) - } - } - } yield { - (JSONFactory300.createCustomersJson(customersFiltered), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getBadLoginStatus, - implementedInApiVersion, - nameOf(getBadLoginStatus), - "GET", - "/users/USERNAME/lock-status", - "Get User Lock Status", - s""" - |Get User Login Status. - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - badLoginStatusJson, - List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError), - List(apiTagUser), - Some(List(canReadUserLockedStatus)) - ) - - lazy val getBadLoginStatus : OBPEndpoint = { - //get private accounts for all banks - case "users" :: username:: "lock-status" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadUserLockedStatus, callContext) - _ <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map { - x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404) - } - badLoginStatus <- Future { LoginAttempt.getOrCreateBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) } - } yield { - (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - unlockUser, - implementedInApiVersion, - nameOf(unlockUser), - "PUT", - "/users/USERNAME/lock-status", - "Unlock the user", - s""" - |Unlock a User. - | - |(Perhaps the user was locked due to multiple failed login attempts) - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - badLoginStatusJson, - List(AuthenticatedUserIsRequired, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError), - List(apiTagUser), - Some(List(canUnlockUser))) - - lazy val unlockUser : OBPEndpoint = { - //get private accounts for all banks - case "users" :: username:: "lock-status" :: Nil JsonPut req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - user <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map { - x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404) - } - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUnlockUser, callContext) - _ <- Future { LoginAttempt.resetBadLoginAttempts(localIdentityProvider,username) } - _ <- Future { UserLocksProvider.unlockUser(localIdentityProvider,username) } - badLoginStatus <- Future { LoginAttempt.getOrCreateBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) } - } yield { - (createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - callsLimit, - implementedInApiVersion, - nameOf(callsLimit), - "PUT", - "/management/consumers/CONSUMER_ID/consumer/call-limits", - "Set Rate Limits (call limits) per Consumer", - s""" - |Set the API rate limiting (call limits) per Consumer: - | - |Rate limits can be set: - | - |Per Second - |Per Minute - |Per Hour - |Per Week - |Per Month - | - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - callLimitPostJson, - callLimitPostJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - InvalidConsumerId, - ConsumerNotFoundByConsumerId, - UserHasMissingRoles, - UpdateConsumerError, - UnknownError - ), - List(apiTagConsumer), - Some(List(canUpdateRateLimits))) - - lazy val callsLimit : OBPEndpoint = { - case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateRateLimits, callContext) - postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $CallLimitPostJson ", 400, callContext) { - json.extract[CallLimitPostJson] - } - _ <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext) - rateLimiting <- RateLimitingDI.rateLimiting.vend.createOrUpdateConsumerCallLimits( - consumerId, - postJson.from_date, - postJson.to_date, - None, - None, - None, - Some(postJson.per_second_call_limit), - Some(postJson.per_minute_call_limit), - Some(postJson.per_hour_call_limit), - Some(postJson.per_day_call_limit), - Some(postJson.per_week_call_limit), - Some(postJson.per_month_call_limit)) map { - unboxFullOrFail(_, callContext, UpdateConsumerError) - } - } yield { - (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getCallsLimit, - implementedInApiVersion, - nameOf(getCallsLimit), - "GET", - "/management/consumers/CONSUMER_ID/consumer/call-limits", - "Get Rate Limits for a Consumer", - s""" - |Get Rate Limits per Consumer. - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - callLimitJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - InvalidConsumerId, - ConsumerNotFoundByConsumerId, - UserHasMissingRoles, - UpdateConsumerError, - UnknownError - ), - List(apiTagConsumer), - Some(List(canUpdateRateLimits))) - - - - lazy val getCallsLimit : OBPEndpoint = { - case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canReadCallLimits, callContext) - consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext) - rateLimit <- Future(RateLimitingUtil.consumerRateLimitState(consumer.consumerId.get).toList) - } yield { - (createCallLimitJson(consumer, rateLimit), HttpCode.`200`(callContext)) - } - } - } - - - - - resourceDocs += ResourceDoc( - checkFundsAvailable, - implementedInApiVersion, - nameOf(checkFundsAvailable), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/funds-available", - "Check Available Funds", - """Check Available Funds - |Mandatory URL parameters: - | - |* amount=NUMBER - |* currency=STRING - | - """.stripMargin, - EmptyBody, - checkFundsAvailableJson, - List( - AuthenticatedUserIsRequired, - BankNotFound, - BankAccountNotFound, - InvalidAmount, - InvalidISOCurrencyCode, - UnknownError - ), - apiTagAccount :: apiTagPSD2PIIS :: apiTagPsd2 :: Nil) - - lazy val checkFundsAvailable : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "funds-available" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - val amount = "amount" - val currency = "currency" - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext) - _ <- Helper.booleanToFuture(failMsg = s"$ViewDoesNotPermitAccess + You need the `${(CAN_QUERY_AVAILABLE_FUNDS)}` permission on any your views", cc=callContext) { - view.allowed_actions.exists(_ ==CAN_QUERY_AVAILABLE_FUNDS) - } - httpParams: List[HTTPParam] <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - _ <- Helper.booleanToFuture(failMsg = MissingQueryParams + amount, cc=callContext) { - httpParams.exists(_.name == amount) - } - _ <- Helper.booleanToFuture(failMsg = MissingQueryParams + currency, cc=callContext) { - httpParams.exists(_.name == currency) - } - available <- NewStyle.function.tryons(s"$InvalidAmount", 400, callContext) { - val value = httpParams.filter(_.name == amount).map(_.values.head).head - new java.math.BigDecimal(value) - } - _ <- NewStyle.function.isValidCurrencyISOCode(httpParams.filter(_.name == currency).map(_.values.head).head, callContext) - _ <- NewStyle.function.moderatedBankAccountCore(account, view, Full(u), callContext) - } yield { - val ccy = httpParams.filter(_.name == currency).map(_.values.head).head - val fundsAvailable = ( view.allowed_actions.exists(_ ==CAN_QUERY_AVAILABLE_FUNDS), account.balance, account.currency) match { - case (false, _, _) => "" // 1st condition: MUST have a view can_query_available_funds - case (true, _, c) if c != ccy => "no" // 2nd condition: Currency has to be matched - case (true, b, _) if b.compare(available) >= 0 => "yes" // We have the vew, the right currency and enough funds - case _ => "no" - } - val availableFundsRequestId = callContext.map(_.correlationId).getOrElse("") - (createCheckFundsAvailableJson(fundsAvailable, availableFundsRequestId), HttpCode.`200`(callContext)) - } - - } - } - - - - resourceDocs += ResourceDoc( - getConsumer, - implementedInApiVersion, - nameOf(getConsumer), - "GET", - "/management/consumers/CONSUMER_ID", - "Get Consumer", - s"""Get the Consumer specified by CONSUMER_ID. - | - |""", - EmptyBody, - consumerJSON, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - ConsumerNotFoundByConsumerId, - UnknownError - ), - List(apiTagConsumer), - Some(List(canGetConsumers))) - - - lazy val getConsumer: OBPEndpoint = { - case "management" :: "consumers" :: consumerId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConsumers, callContext) - consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext) - user <- Users.users.vend.getUserByUserIdFuture(consumer.createdByUserId.get) - } yield { - (createConsumerJSON(consumer, user), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getConsumersForCurrentUser, - implementedInApiVersion, - nameOf(getConsumersForCurrentUser), - "GET", - "/management/users/current/consumers", - "Get Consumers (logged in User)", - s"""Get the Consumers for logged in User. - | - |""", - EmptyBody, - consumersJson310, - List( - AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagConsumer) - ) - - - lazy val getConsumersForCurrentUser: OBPEndpoint = { - case "management" :: "users" :: "current" :: "consumers" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - consumer <- Consumers.consumers.vend.getConsumersByUserIdFuture(u.userId) - } yield { - (createConsumersJson(consumer, Full(u)), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getConsumers, - implementedInApiVersion, - nameOf(getConsumers), - "GET", - "/management/consumers", - "Get Consumers", - s"""Get the all Consumers. - | - |${userAuthenticationMessage(true)} - | - |${urlParametersDocument(true, true)} - | - |""", - EmptyBody, - consumersJson310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagConsumer), - Some(List(canGetConsumers)) - ) - - - lazy val getConsumers: OBPEndpoint = { - case "management" :: "consumers" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConsumers, callContext) - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext) - consumers <- Consumers.consumers.vend.getConsumersFuture(obpQueryParams, callContext) - users <- Users.users.vend.getUsersByUserIdsFuture(consumers.map(_.createdByUserId.get)) - } yield { - (createConsumersJson(consumers, users), HttpCode.`200`(callContext)) - } - } - } - - - val accountWebHookInfo = s"""Webhooks are used to call external URLs when certain events happen. - | - |Account Webhooks focus on events around accounts. - | - |For instance, a webhook could be used to notify an external service if a balance changes on an account. - | - |This functionality is work in progress! Please note that only implemented trigger is: ${ApiTrigger.onBalanceChange}""" - - - resourceDocs += ResourceDoc( - createAccountWebhook, - implementedInApiVersion, - nameOf(createAccountWebhook), - "POST", - "/banks/BANK_ID/account-web-hooks", - "Create an Account Webhook", - s"""Create an Account Webhook - | - |$accountWebHookInfo - |""", - accountWebhookPostJson, - accountWebhookJson, - List(UnknownError), - apiTagWebhook :: apiTagBank :: Nil, - Some(List(canCreateWebhook)) - ) - - lazy val createAccountWebhook : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "account-web-hooks" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canCreateWebhook, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountWebhookPostJson " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountWebhookPostJson] - } - failMsg = IncorrectTriggerName + postJson.trigger_name + ". Possible values are " + ApiTrigger.availableTriggers.sorted.mkString(", ") - _ <- NewStyle.function.tryons(failMsg, 400, callContext) { - ApiTrigger.valueOf(postJson.trigger_name) - } - failMsg = s"$InvalidBoolean Possible values of the json field is_active are true or false." - isActive <- NewStyle.function.tryons(failMsg, 400, callContext) { - postJson.is_active.toBoolean - } - wh <- AccountWebhook.accountWebhook.vend.createAccountWebhookFuture( - bankId = bankId.value, - accountId = postJson.account_id, - userId = u.userId, - triggerName = postJson.trigger_name, - url = postJson.url, - httpMethod = postJson.http_method, - httpProtocol = postJson.http_protocol, - isActive = isActive - ) map { - unboxFullOrFail(_, callContext, CreateWebhookError) - } - } yield { - (createAccountWebhookJson(wh), HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - enableDisableAccountWebhook, - implementedInApiVersion, - nameOf(enableDisableAccountWebhook), - "PUT", - "/banks/BANK_ID/account-web-hooks", - "Enable/Disable an Account Webhook", - s"""Enable/Disable an Account Webhook - | - | - |$accountWebHookInfo - |""", - accountWebhookPutJson, - accountWebhookJson, - List(UnknownError), - apiTagWebhook :: apiTagBank :: Nil, - Some(List(canUpdateWebhook)) - ) - - lazy val enableDisableAccountWebhook : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "account-web-hooks" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateWebhook, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountWebhookPutJson " - putJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountWebhookPutJson] - } - failMsg = s"$InvalidBoolean Possible values of the json field is_active are true or false." - isActive <- NewStyle.function.tryons(failMsg, 400, callContext) { - putJson.is_active.toBoolean - } - _ <- AccountWebhook.accountWebhook.vend.getAccountWebhookByIdFuture(putJson.account_webhook_id) map { - unboxFullOrFail(_, callContext, WebhookNotFound) - } - wh <- AccountWebhook.accountWebhook.vend.updateAccountWebhookFuture( - accountWebhookId = putJson.account_webhook_id, - isActive = isActive - ) map { - unboxFullOrFail(_, callContext, UpdateWebhookError) - } - } yield { - (createAccountWebhookJson(wh), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getAccountWebhooks, - implementedInApiVersion, - nameOf(getAccountWebhooks), - "GET", - "/management/banks/BANK_ID/account-web-hooks", - "Get Account Webhooks", - s"""Get Account Webhooks. - | - |Possible custom URL parameters for pagination: - | - |${urlParametersDocument(false, false)} - |* account_id=STRING (if null ignore) - |* user_id=STRING (if null ignore) - | - | - |""", - EmptyBody, - accountWebhooksJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - apiTagWebhook :: apiTagBank :: Nil, - Some(List(canGetWebhooks)) - ) - - - lazy val getAccountWebhooks: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) ::"account-web-hooks" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetWebhooks, callContext) - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - allowedParams = List("limit", "offset", "account_id", "user_id") - (obpParams, callContext) <- NewStyle.function.createObpParams(httpParams, allowedParams, callContext) - additionalParam = OBPBankId(bankId.value) - webhooks <- NewStyle.function.getAccountWebhooks(additionalParam :: obpParams, callContext) - } yield { - (createAccountWebhooksJson(webhooks), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - config, - implementedInApiVersion, - nameOf(config), - "GET", - "/config", - "Get API Configuration", - """Returns information about: - | - |* The default bank_id - |* Akka configuration - |* Elastic Search configuration - |* Cached functions """, - EmptyBody, - configurationJSON, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - apiTagApi :: Nil, - Some(List(canGetConfig))) - - lazy val config: OBPEndpoint = { - case "config" :: Nil JsonGet _ => - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConfig, callContext) - } yield { - (JSONFactory310.getConfigInfoJSON(), HttpCode.`200`(callContext)) - } - } - - resourceDocs += ResourceDoc( - getAdapterInfo, - implementedInApiVersion, - nameOf(getAdapterInfo), - "GET", - "/adapter", - "Get Adapter Info", - s"""Get basic information about the Adapter. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - adapterInfoJsonV300, - List(AuthenticatedUserIsRequired,UserHasMissingRoles, UnknownError), - List(apiTagApi), - Some(List(canGetAdapterInfo)) - ) - - - lazy val getAdapterInfo: OBPEndpoint = { - case "adapter" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetAdapterInfo, callContext) - (ai,_) <- NewStyle.function.getAdapterInfo(callContext) - } yield { - (createAdapterInfoJson(ai), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getTransactionByIdForBankAccount, - implementedInApiVersion, - nameOf(getTransactionByIdForBankAccount), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/transaction", - "Get Transaction by Id", - s"""Returns one transaction specified by TRANSACTION_ID of the account ACCOUNT_ID and [moderated](#1_2_1-getViewsForBankAccount) by the view (VIEW_ID). - | - |${userAuthenticationMessage(false)} - |Authentication is required if the view is not public. - | - | - |""", - EmptyBody, - transactionJsonV300, - List(AuthenticatedUserIsRequired, BankAccountNotFound ,ViewNotFound, UserNoPermissionAccessView, UnknownError), - List(apiTagTransaction)) - - lazy val getTransactionByIdForBankAccount : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transactions" :: TransactionId(transactionId) :: "transaction" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (user, callContext) <- authenticatedAccess(cc) - _ <- passesPsd2Pisp(callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), user, callContext) - (moderatedTransaction, callContext) <- account.moderatedTransactionFuture(transactionId, view, user, callContext) map { - unboxFullOrFail(_, callContext, GetTransactionsException) - } - (transactionAttributes, callContext) <- NewStyle.function.getTransactionAttributes( - bankId, - transactionId, - callContext: Option[CallContext]) - } yield { - (JSONFactory300.createTransactionJSON(moderatedTransaction, transactionAttributes), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getTransactionRequests, - implementedInApiVersion, - nameOf(getTransactionRequests), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests", - "Get Transaction Requests." , - """Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID. - | - |The VIEW_ID specified must be 'owner' and the user must have access to this view. - | - |Version 2.0.0 now returns charge information. - | - |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including: - | - |* Transaction Request Id - |* Type - |* Status (INITIATED, COMPLETED) - |* Challenge (in order to confirm the request) - |* From Bank / Account - |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.) - |* Related Transactions - | - |PSD2 Context: PSD2 requires transparency of charges to the customer. - |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after. - |The customer can proceed with the Transaction by answering the security challenge. - | - """.stripMargin, - EmptyBody, - transactionRequestWithChargeJSONs210, - List( - AuthenticatedUserIsRequired, - BankNotFound, - BankAccountNotFound, - UserNoPermissionAccessView, - ViewDoesNotPermitAccess, - GetTransactionRequestsException, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS)) - - lazy val getTransactionRequests: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-requests" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.isEnabledTransactionRequests(callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - view <- ViewNewStyle.checkAccountAccessAndGetView(viewId, BankIdAccountId(bankId, accountId), Full(u), callContext) - _ <- Helper.booleanToFuture( - s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})", - cc=callContext){ - view.allowed_actions.exists(_ ==CAN_SEE_TRANSACTION_REQUESTS) - } - (transactionRequests, callContext) <- Future(Connector.connector.vend.getTransactionRequests210(u, fromAccount, callContext)) map { - unboxFullOrFail(_, callContext, GetTransactionRequestsException) - } - } yield { - val json = JSONFactory210.createTransactionRequestJSONs(transactionRequests) - (json, HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createCustomer, - implementedInApiVersion, - nameOf(createCustomer), - "POST", - "/banks/BANK_ID/customers", - "Create Customer", - s""" - |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc. - |Dates need to be in the format 2013-01-21T23:08:00Z - | - |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call. - | - |${userAuthenticationMessage(true)} - |""", - postCustomerJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - CustomerNumberAlreadyExists, - UserNotFoundById, - CustomerAlreadyExistsForUser, - CreateCustomerError, - UnknownError - ), - List(apiTagCustomer, apiTagPerson), - Some(List(canCreateCustomer,canCreateCustomerAtAnyBank)) - ) - lazy val createCustomer : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, canCreateCustomer :: canCreateCustomerAtAnyBank :: Nil, callContext) - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostCustomerJsonV310] - } - _ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants}) not equal the length(${postedData.dob_of_dependants.length }) of dob_of_dependants array", cc=callContext) { - postedData.dependants == postedData.dob_of_dependants.length - } - (customer, callContext) <- NewStyle.function.createCustomer( - bankId, - postedData.legal_name, - postedData.mobile_phone_number, - postedData.email, - CustomerFaceImage(postedData.face_image.date, postedData.face_image.url), - postedData.date_of_birth, - postedData.relationship_status, - postedData.dependants, - postedData.dob_of_dependants, - postedData.highest_education_attained, - postedData.employment_status, - postedData.kyc_status, - postedData.last_ok_date, - Option(CreditRating(postedData.credit_rating.rating, postedData.credit_rating.source)), - Option(CreditLimit(postedData.credit_limit.currency, postedData.credit_limit.amount)), - postedData.title, - postedData.branch_id, - postedData.name_suffix, - callContext, - ) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`201`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getRateLimitingInfo, - implementedInApiVersion, - nameOf(getRateLimitingInfo), - "GET", - "/rate-limiting", - "Get Rate Limiting Info", - s"""Get information about the Rate Limiting setup on this OBP Instance such as: - | - |Is rate limiting enabled and active? - |What backend is used to keep track of the API calls (e.g. REDIS). - | - |Note: Rate limiting can be set at the Consumer level and also for anonymous calls. - | - |See the consumer rate limits / call limits endpoints. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - rateLimitingInfoV310, - List(UnknownError), - List(apiTagApi, apiTagRateLimits)) - - - lazy val getRateLimitingInfo: OBPEndpoint = { - case "rate-limiting" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- anonymousAccess(cc) - rateLimiting <- NewStyle.function.tryons("", 400, callContext) { - val isActive = if (RateLimitingUtil.useConsumerLimits ) true else false - RateLimiting(RateLimitingUtil.useConsumerLimits, "REDIS", true, isActive) - } - } yield { - (createRateLimitingInfo(rateLimiting), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getCustomerByCustomerId, - implementedInApiVersion, - nameOf(getCustomerByCustomerId), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID", - "Get Customer by CUSTOMER_ID", - s"""Gets the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerWithAttributesJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer), - Some(List(canGetCustomersAtOneBank))) - - lazy val getCustomerByCustomerId : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomersAtOneBank, callContext) - (customer, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes( - bankId, - CustomerId(customerId), - callContext: Option[CallContext]) - } yield { - (JSONFactory310.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getCustomerByCustomerNumber, - implementedInApiVersion, - nameOf(getCustomerByCustomerNumber), - "POST", - "/banks/BANK_ID/customers/customer-number", - "Get Customer by CUSTOMER_NUMBER", - s"""Gets the Customer specified by CUSTOMER_NUMBER. - | - | - |${userAuthenticationMessage(true)} - | - |""", - postCustomerNumberJsonV310, - customerWithAttributesJsonV310, - List( - AuthenticatedUserIsRequired, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer, apiTagKyc), - Some(List(canGetCustomersAtOneBank)) - ) - - lazy val getCustomerByCustomerNumber : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: "customer-number" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomersAtOneBank, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerNumberJsonV310 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostCustomerNumberJsonV310] - } - (customer, callContext) <- NewStyle.function.getCustomerByCustomerNumber(postedData.customer_number, bank.bankId, callContext) - (customerAttributes, callContext) <- NewStyle.function.getCustomerAttributes( - bankId, - CustomerId(customer.customerId), - callContext: Option[CallContext]) - } yield { - (JSONFactory310.createCustomerWithAttributesJson(customer, customerAttributes), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createUserAuthContext, - implementedInApiVersion, - nameOf(createUserAuthContext), - "POST", - "/users/USER_ID/auth-context", - "Create User Auth Context", - s"""Create User Auth Context. These key value pairs will be propagated over connector to adapter. Normally used for mapping OBP user and - | Bank User/Customer. - |${userAuthenticationMessage(true)} - |""", - postUserAuthContextJson, - userAuthContextJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - CreateUserAuthContextError, - UnknownError - ), - List(apiTagUser), - Some(List(canCreateUserAuthContext))) - - lazy val createUserAuthContext : OBPEndpoint = { - case "users" :: userId ::"auth-context" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateUserAuthContext, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostUserAuthContextJson] - } - (user, callContext) <- NewStyle.function.findByUserId(userId, callContext) - (userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key.trim, postedData.value.trim, callContext) - } yield { - (JSONFactory310.createUserAuthContextJson(userAuthContext), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getUserAuthContexts, - implementedInApiVersion, - nameOf(getUserAuthContexts), - "GET", - "/users/USER_ID/auth-context", - "Get User Auth Contexts", - s"""Get User Auth Contexts for a User. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - userAuthContextsJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(canGetUserAuthContext :: Nil) - ) - - lazy val getUserAuthContexts : OBPEndpoint = { - case "users" :: userId :: "auth-context" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canGetUserAuthContext, callContext) - (_, callContext) <- NewStyle.function.findByUserId(userId, callContext) - (userAuthContexts, callContext) <- NewStyle.function.getUserAuthContexts(userId, callContext) - } yield { - (JSONFactory310.createUserAuthContextsJson(userAuthContexts), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - deleteUserAuthContexts, - implementedInApiVersion, - nameOf(deleteUserAuthContexts), - "DELETE", - "/users/USER_ID/auth-context", - "Delete User's Auth Contexts", - s"""Delete the Auth Contexts of a User specified by USER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canDeleteUserAuthContext))) - - lazy val deleteUserAuthContexts : OBPEndpoint = { - case "users" :: userId :: "auth-context" :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteUserAuthContext, callContext) - (_, callContext) <- NewStyle.function.findByUserId(userId, callContext) - (userAuthContext, callContext) <- NewStyle.function.deleteUserAuthContexts(userId, callContext) - } yield { - (Full(userAuthContext), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - deleteUserAuthContextById, - implementedInApiVersion, - nameOf(deleteUserAuthContextById), - "DELETE", - "/users/USER_ID/auth-context/USER_AUTH_CONTEXT_ID", - "Delete User Auth Context", - s"""Delete a User AuthContext of the User specified by USER_AUTH_CONTEXT_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canDeleteUserAuthContext))) - - lazy val deleteUserAuthContextById : OBPEndpoint = { - case "users" :: userId :: "auth-context" :: userAuthContextId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteUserAuthContext, callContext) - (user, callContext) <- NewStyle.function.findByUserId(userId, callContext) - (userAuthContext, callContext) <- NewStyle.function.deleteUserAuthContextById(user, userAuthContextId, callContext) - } yield { - (Full(userAuthContext), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createTaxResidence, - implementedInApiVersion, - nameOf(createTaxResidence), - "POST", - "/banks/BANK_ID/customers/CUSTOMER_ID/tax-residence", - "Create Tax Residence", - s"""Create a Tax Residence for a Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - postTaxResidenceJsonV310, - taxResidenceV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagKyc), - Some(List(canCreateTaxResidence))) - - lazy val createTaxResidence : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax-residence" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateTaxResidence, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostTaxResidenceJsonV310 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostTaxResidenceJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (taxResidence, callContext) <- NewStyle.function.createTaxResidence(customerId, postedData.domain, postedData.tax_number, callContext) - } yield { - (JSONFactory310.createTaxResidence(taxResidence), HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getTaxResidence, - implementedInApiVersion, - nameOf(getTaxResidence), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/tax-residences", - "Get Tax Residences of Customer", - s"""Get the Tax Residences of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - taxResidencesJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer, apiTagKyc)) - - lazy val getTaxResidence : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax-residences" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetTaxResidence, callContext) - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (taxResidences, callContext) <- NewStyle.function.getTaxResidences(customerId, callContext) - } yield { - (JSONFactory310.createTaxResidences(taxResidences), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - deleteTaxResidence, - implementedInApiVersion, - nameOf(deleteTaxResidence), - "DELETE", - "/banks/BANK_ID/customers/CUSTOMER_ID/tax_residencies/TAX_RESIDENCE_ID", - "Delete Tax Residence", - s"""Delete a Tax Residence of the Customer specified by TAX_RESIDENCE_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer, apiTagKyc)) - - lazy val deleteTaxResidence : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "tax_residencies" :: taxResidenceId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteTaxResidence, callContext) - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (taxResidence, callContext) <- NewStyle.function.deleteTaxResidence(taxResidenceId, callContext) - } yield { - (Full(taxResidence), HttpCode.`200`(callContext)) - } - } - } - resourceDocs += ResourceDoc( - getAllEntitlements, - implementedInApiVersion, - nameOf(getAllEntitlements), - "GET", - "/entitlements", - "Get all Entitlements", - s""" - | - |Login is required. - | - |Possible filter on the role field: - | - |eg: /entitlements?role=${canGetCustomersAtOneBank.toString} - | - | - | - """.stripMargin, - EmptyBody, - entitlementJSonsV310, - List(AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError), - List(apiTagRole, apiTagEntitlement)) - - - lazy val getAllEntitlements: OBPEndpoint = { - case "entitlements" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canGetEntitlementsForAnyUserAtAnyBank, callContext) - roleName = APIUtil.getHttpRequestUrlParam(cc.url, "role") - entitlements <- Entitlement.entitlement.vend.getEntitlementsByRoleFuture(roleName) map { - connectorEmptyResponse(_, callContext) - } - } yield { - (JSONFactory310.createEntitlementJsonsV310(entitlements), callContext) - } - } - } - - - - resourceDocs += ResourceDoc( - createCustomerAddress, - implementedInApiVersion, - nameOf(createCustomerAddress), - "POST", - "/banks/BANK_ID/customers/CUSTOMER_ID/address", - "Create Address", - s"""Create an Address for a Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - postCustomerAddressJsonV310, - customerAddressJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(List(canCreateCustomerAddress))) - - lazy val createCustomerAddress : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "address" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateCustomerAddress, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerAddressJsonV310 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostCustomerAddressJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (address, callContext) <- NewStyle.function.createCustomerAddress( - customerId, - postedData.line_1, - postedData.line_2, - postedData.line_3, - postedData.city, - postedData.county, - postedData.state, - postedData.postcode, - postedData.country_code, - postedData.state, - postedData.tags.mkString(","), - callContext) - } yield { - (JSONFactory310.createAddress(address), HttpCode.`201`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - updateCustomerAddress, - implementedInApiVersion, - nameOf(updateCustomerAddress), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID", - "Update the Address of a Customer", - s"""Update an Address of the Customer specified by CUSTOMER_ADDRESS_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - postCustomerAddressJsonV310, - customerAddressJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer)) - - lazy val updateCustomerAddress : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: customerAddressId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canCreateCustomer, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerAddressJsonV310 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostCustomerAddressJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (address, callContext) <- NewStyle.function.updateCustomerAddress( - customerAddressId, - postedData.line_1, - postedData.line_2, - postedData.line_3, - postedData.city, - postedData.county, - postedData.state, - postedData.postcode, - postedData.country_code, - postedData.state, - postedData.tags.mkString(","), - callContext) - } yield { - (JSONFactory310.createAddress(address), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getCustomerAddresses, - implementedInApiVersion, - nameOf(getCustomerAddresses), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/addresses", - "Get Customer Addresses", - s"""Get the Addresses of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerAddressesJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer, apiTagKyc), - Some(List(canGetCustomerAddress))) - - lazy val getCustomerAddresses : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomerAddress, callContext) - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customers, callContext) <- NewStyle.function.getCustomerAddress(customerId, callContext) - } yield { - (JSONFactory310.createAddresses(customers), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - deleteCustomerAddress, - implementedInApiVersion, - nameOf(deleteCustomerAddress), - "DELETE", - "/banks/BANK_ID/customers/CUSTOMER_ID/addresses/CUSTOMER_ADDRESS_ID", - "Delete Customer Address", - s"""Delete an Address of the Customer specified by CUSTOMER_ADDRESS_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer, apiTagKyc), - Some(List(canDeleteCustomerAddress))) - - lazy val deleteCustomerAddress : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "addresses" :: customerAddressId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canDeleteCustomerAddress, callContext) - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (address, callContext) <- NewStyle.function.deleteCustomerAddress(customerAddressId, callContext) - } yield { - (Full(address), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getObpConnectorLoopback, - implementedInApiVersion, - nameOf(getObpConnectorLoopback), - "GET", - "/connector/loopback", - "Get Connector Status (Loopback)", - s"""This endpoint makes a call to the Connector to check the backend transport is reachable. (Deprecated) - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - obpApiLoopbackJson, - List( - UnknownError - ), - List(apiTagApi, apiTagOAuth, apiTagOIDC)) - - lazy val getObpConnectorLoopback : OBPEndpoint = { - case "connector" :: "loopback" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- anonymousAccess(cc) - connectorVersion = code.api.Constant.CONNECTOR.openOrThrowException(s"$MandatoryPropertyIsNotSet The missing props is 'connector'") - starConnectorProps = APIUtil.getPropsValue("starConnector_supported_types").openOr("notfound") - //TODO we need to decide what kind of connector should we use. - obpApiLoopback = ObpApiLoopback( - connectorVersion ="Unknown", - gitCommit ="Unknown", - durationTime ="Unknown" - ) - _ = throw new IllegalStateException(s"${NotImplemented}") - } yield { - (createObpApiLoopbackJson(obpApiLoopback), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - refreshUser, - implementedInApiVersion, - nameOf(refreshUser), - "POST", - "/users/USER_ID/refresh", - "Refresh User", - s""" The endpoint is used for updating the accounts, views, account holders for the user. - | As to the Json body, you can leave it as Empty. - | This call will get data from backend, no need to prepare the json body in api side. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - refresUserJson, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canRefreshUser)) - ) - - lazy val refreshUser : OBPEndpoint = { - case "users" :: userId :: "refresh" :: Nil JsonPost _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canRefreshUser, callContext) - startTime <- Future{Helpers.now} - (user, callContext) <- NewStyle.function.findByUserId(userId, callContext) - _ <- AuthUser.refreshUser(user, callContext) - endTime <- Future{Helpers.now} - durationTime = endTime.getTime - startTime.getTime - } yield { - (createRefreshUserJson(durationTime), HttpCode.`201`(callContext)) - } - } - } - - - val productAttributeGeneralInfo = - s""" - |Product Attributes are used to describe a financial Product with a list of typed key value pairs. - | - |Each Product Attribute is linked to its Product by PRODUCT_CODE - | - | - """.stripMargin - - resourceDocs += ResourceDoc( - createProductAttribute, - implementedInApiVersion, - nameOf(createProductAttribute), - "POST", - "/banks/BANK_ID/products/PRODUCT_CODE/attribute", - "Create Product Attribute", - s""" Create Product Attribute - | - |$productAttributeGeneralInfo - | - |Typical product attributes might be: - | - |ISIN (for International bonds) - |VKN (for German bonds) - |REDCODE (markit short code for credit derivative) - |LOAN_ID (e.g. used for Anacredit reporting) - | - |ISSUE_DATE (When the bond was issued in the market) - |MATURITY_DATE (End of life time of a product) - |TRADABLE - | - |See [FPML](http://www.fpml.org/) for more examples. - | - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - | - | - |${userAuthenticationMessage(true)} - | - |""", - productAttributeJson, - productAttributeResponseJson, - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canCreateProductAttribute)) - ) - - lazy val createProductAttribute : OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode:: "attribute" :: Nil JsonPost json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canCreateProductAttribute, callContext) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[ProductAttributeJson] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" - productAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - ProductAttributeType.withName(postedData.`type`) - } - - (productAttribute, callContext) <- NewStyle.function.createOrUpdateProductAttribute( - BankId(bankId), - ProductCode(productCode), - None, - postedData.name, - productAttributeType, - postedData.value, - None, - callContext: Option[CallContext] - ) - } yield { - (createProductAttributeJson(productAttribute), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getProductAttribute, - implementedInApiVersion, - nameOf(getProductAttribute), - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", - "Get Product Attribute", - s""" Get Product Attribute - | - |$productAttributeGeneralInfo - | - |Get one product attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - productAttributeResponseJson, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canGetProductAttribute)) - ) - - lazy val getProductAttribute : OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canGetProductAttribute, callContext) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - (productAttribute, callContext) <- NewStyle.function.getProductAttributeById(productAttributeId, callContext) - - } yield { - (createProductAttributeJson(productAttribute), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateProductAttribute, - implementedInApiVersion, - nameOf(updateProductAttribute), - "PUT", - "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", - "Update Product Attribute", - s""" Update Product Attribute. - | - - |$productAttributeGeneralInfo - | - |Update one Product Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - productAttributeJson, - productAttributeResponseJson, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canUpdateProductAttribute)) - ) - - lazy val updateProductAttribute : OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonPut json -> _ =>{ - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canUpdateProductAttribute, callContext) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[ProductAttributeJson] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" - productAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - ProductAttributeType.withName(postedData.`type`) - } - (_, callContext) <- NewStyle.function.getProductAttributeById(productAttributeId, callContext) - (productAttribute, callContext) <- NewStyle.function.createOrUpdateProductAttribute( - BankId(bankId), - ProductCode(productCode), - Some(productAttributeId), - postedData.name, - productAttributeType, - postedData.value, - None, - callContext: Option[CallContext] - ) - } yield { - (createProductAttributeJson(productAttribute), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - deleteProductAttribute, - implementedInApiVersion, - nameOf(deleteProductAttribute), - "DELETE", - "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", - "Delete Product Attribute", - s""" Delete Product Attribute - | - |$productAttributeGeneralInfo - | - |Delete a Product Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - UserHasMissingRoles, - BankNotFound, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canUpdateProductAttribute))) - - lazy val deleteProductAttribute : OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode:: "attributes" :: productAttributeId :: Nil JsonDelete _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canDeleteProductAttribute, callContext) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - (productAttribute, callContext) <- NewStyle.function.deleteProductAttribute(productAttributeId, callContext) - } yield { - (Full(productAttribute), HttpCode.`204`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createAccountApplication, - implementedInApiVersion, - nameOf(createAccountApplication), - "POST", - "/banks/BANK_ID/account-applications", - "Create Account Application", - s""" Create Account Application - | - |${userAuthenticationMessage(true)} - | - |""", - accountApplicationJson, - accountApplicationResponseJson, - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagAccountApplication, apiTagAccount)) - - lazy val createAccountApplication : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "account-applications" :: Nil JsonPost json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountApplicationJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountApplicationJson] - } - - illegalProductCodeMsg = s"$InvalidJsonFormat product_code should not be empty." - _ <- NewStyle.function.tryons(illegalProductCodeMsg, 400, callContext) { - Validate.notBlank(postedData.product_code) - } - - illegalUserIdOrCustomerIdMsg = s"$InvalidJsonFormat User_id and customer_id should not both are empty." - _ <- NewStyle.function.tryons(illegalUserIdOrCustomerIdMsg, 400, callContext) { - Validate.isTrue(postedData.user_id.isDefined || postedData.customer_id.isDefined) - } - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - user <- unboxOptionOBPReturnType(postedData.user_id.map(NewStyle.function.findByUserId(_, callContext))) - - customer <- unboxOptionOBPReturnType(postedData.customer_id.map(NewStyle.function.getCustomerByCustomerId(_, callContext))) - - (productAttribute, callContext) <- NewStyle.function.createAccountApplication( - productCode = ProductCode(postedData.product_code), - userId = postedData.user_id, - customerId = postedData.customer_id, - callContext = callContext - ) - } yield { - (createAccountApplicationJson(productAttribute, user, customer), HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getAccountApplications, - implementedInApiVersion, - nameOf(getAccountApplications), - "GET", - "/banks/BANK_ID/account-applications", - "Get Account Applications", - s"""Get the Account Applications. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - accountApplicationsJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagAccountApplication, apiTagAccount)) - - lazy val getAccountApplications : OBPEndpoint = { - case "banks" :: BankId(bankId) ::"account-applications" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - _ <- NewStyle.function.hasEntitlement("", u.userId, canGetAccountApplications, callContext) - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - (accountApplications, _) <- NewStyle.function.getAllAccountApplication(callContext) - (users, _) <- NewStyle.function.findUsers(accountApplications.map(_.userId), callContext) - (customers, _) <- NewStyle.function.findCustomers(accountApplications.map(_.customerId), callContext) - } yield { - (JSONFactory310.createAccountApplications(accountApplications, users, customers), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getAccountApplication, - implementedInApiVersion, - nameOf(getAccountApplication), - "GET", - "/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID", - "Get Account Application by Id", - s"""Get the Account Application. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - accountApplicationResponseJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagAccountApplication, apiTagAccount)) - - lazy val getAccountApplication : OBPEndpoint = { - case "banks" :: BankId(bankId) ::"account-applications":: accountApplicationId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - (accountApplication, _) <- NewStyle.function.getAccountApplicationById(accountApplicationId, callContext) - - userId = Option(accountApplication.userId) - customerId = Option(accountApplication.customerId) - - user <- unboxOptionOBPReturnType(userId.map(NewStyle.function.findByUserId(_, callContext))) - customer <- unboxOptionOBPReturnType(customerId.map(NewStyle.function.getCustomerByCustomerId(_, callContext))) - - } yield { - (createAccountApplicationJson(accountApplication, user, customer), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - updateAccountApplicationStatus, - implementedInApiVersion, - nameOf(updateAccountApplicationStatus), - "PUT", - "/banks/BANK_ID/account-applications/ACCOUNT_APPLICATION_ID", - "Update Account Application Status", - s"""Update an Account Application status - | - | - |${userAuthenticationMessage(true)} - | - |""", - accountApplicationUpdateStatusJson, - accountApplicationResponseJson, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagAccountApplication, apiTagAccount) - ) - - lazy val updateAccountApplicationStatus : OBPEndpoint = { - case "banks" :: BankId(bankId) ::"account-applications" :: accountApplicationId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUpdateAccountApplications, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountApplicationUpdateStatusJson " - putJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountApplicationUpdateStatusJson] - } - - failMsg = s"$InvalidJsonFormat status should not be blank." - status <- NewStyle.function.tryons(failMsg, 400, callContext) { - Validate.notBlank(putJson.status) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - - (accountApplication, _) <- NewStyle.function.getAccountApplicationById(accountApplicationId, callContext) - - (accountApplication, _) <- NewStyle.function.updateAccountApplicationStatus(accountApplicationId, status, callContext) - - userId = Option(accountApplication.userId) - customerId = Option(accountApplication.customerId) - - user <- unboxOptionOBPReturnType(userId.map(NewStyle.function.findByUserId(_, callContext))) - customer <- unboxOptionOBPReturnType(customerId.map(NewStyle.function.getCustomerByCustomerId(_, callContext))) - - _ <- status match { - case "ACCEPTED" => - for{ - accountId <- Future{AccountId(UUID.randomUUID().toString)} - (_, callContext) <- NewStyle.function.createBankAccount( - bankId, - accountId, - accountApplication.productCode.value, - "", - "EUR", - BigDecimal("0"), - u.name, - "", - List.empty, - callContext) - success <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(bankId, accountId, u, callContext) - }yield { - success - } - case _ => Future{""} - } - - } yield { - (createAccountApplicationJson(accountApplication, user, customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createProduct, - implementedInApiVersion, - "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 - | - | - |${userAuthenticationMessage(true) } - | - | - |""", - postPutProductJsonV310, - productJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct), - Some(List(canCreateProduct, canCreateProductAtAnyBank)) - ) - - lazy val createProduct: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostPutProductJsonV310 " - product <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostPutProductJsonV310] - } - (parentProduct,callContext) <- product.parent_product_code.trim.nonEmpty match { - case false => - Future((Empty,callContext)) - case true => - NewStyle.function.getProduct(bankId, ProductCode(product.parent_product_code), callContext).map(product=> (Full(product._1), callContext)) - } - (success, callContext) <- NewStyle.function.createOrUpdateProduct( - bankId = bankId.value, - code = productCode.value, - parentProductCode = parentProduct.map(_.code.value).toOption, - name = product.name, - category = product.category, - family = product.family, - superFamily = product.super_family, - moreInfoUrl = product.more_info_url, - termsAndConditionsUrl = null, - details = product.details, - description = product.description, - metaLicenceId = product.meta.license.id, - metaLicenceName = product.meta.license.name, - callContext - ) - } yield { - (JSONFactory310.createProductJson(success), HttpCode.`201`(callContext)) - } - - } - } - - - resourceDocs += ResourceDoc( - getProduct, - implementedInApiVersion, - "getProduct", - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE", - "Get Bank Product", - s"""Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including: - | - |* Name - |* Code - |* Parent Product Code - |* Category - |* Family - |* Super Family - |* More info URL - |* Description - |* Terms and Conditions - |* License the data under this endpoint is released under - | - |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, - EmptyBody, - productJsonV310, - List( - AuthenticatedUserIsRequired, - ProductNotFoundByProductCode, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProduct: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonGet _ => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (product, callContext)<- NewStyle.function.getProduct(bankId, productCode, callContext) - (productAttributes, callContext) <- NewStyle.function.getProductAttributesByBankAndCode(bankId, productCode, callContext) - } yield { - (JSONFactory310.createProductJson(product, productAttributes), HttpCode.`200`(callContext)) - } - } - } - } - - resourceDocs += ResourceDoc( - getProductTree, - implementedInApiVersion, - nameOf(getProductTree), - "GET", - "/banks/BANK_ID/product-tree/PRODUCT_CODE", - "Get Product Tree", - s"""Returns information about a particular financial product specified by BANK_ID and PRODUCT_CODE - |and it's parent product(s) recursively as specified by parent_product_code. - | - |Each product includes the following information. - | - |* Name - |* Code - |* Parent Product Code - |* Category - |* Family - |* Super Family - |* More info URL - |* Description - |* Terms and Conditions - |* License: The licence under which this product data is released. Licence can be an Open Data licence such as Open Data Commons Public Domain Dedication and License (PDDL) or Copyright etc. - | - | - | - |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, - EmptyBody, - childProductTreeJsonV310, - List( - AuthenticatedUserIsRequired, - ProductNotFoundByProductCode, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProductTree: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "product-tree" :: ProductCode(productCode) :: Nil JsonGet _ => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (_, callContext) <- NewStyle.function.getProduct(bankId, productCode, callContext) - (products,callContext) <- NewStyle.function.getProductTree(bankId, productCode, callContext) - } yield { - (JSONFactory310.createProductTreeJson(products, productCode.value), HttpCode.`200`(callContext)) - } - } - } - } - - resourceDocs += ResourceDoc( - getProducts, - implementedInApiVersion, - "getProducts", - "GET", - "/banks/BANK_ID/products", - "Get Products", - s"""Returns information about the financial products offered by a bank specified by BANK_ID including: - | - |* Name - |* Code - |* Parent Product Code - |* Category - |* Family - |* Super Family - |* More info URL - |* Description - |* Terms and Conditions - |* License the data under this endpoint is released under - | - |Can filter with attributes name and values. - |URL params example: /banks/some-bank-id/products?&limit=50&offset=1 - | - |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, - EmptyBody, - productsJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - ProductNotFoundByProductCode, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProducts : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2)) - (products, callContext) <- NewStyle.function.getProducts(bankId, params, callContext) - } yield { - (JSONFactory310.createProductsJson(products), HttpCode.`200`(callContext)) - } - } - } - } - - - - - - - val accountAttributeGeneralInfo = - s""" - |Account Attributes are used to describe a financial Product with a list of typed key value pairs. - | - |Each Account Attribute is linked to its Account by ACCOUNT_ID - | - | - """.stripMargin - - resourceDocs += ResourceDoc( - createAccountAttribute, - implementedInApiVersion, - nameOf(createAccountAttribute), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attribute", - "Create Account Attribute", - s""" Create Account Attribute - | - |$accountAttributeGeneralInfo - | - |Typical account attributes might be: - | - |ISIN (for International bonds) - |VKN (for German bonds) - |REDCODE (markit short code for credit derivative) - |LOAN_ID (e.g. used for Anacredit reporting) - | - |ISSUE_DATE (When the bond was issued in the market) - |MATURITY_DATE (End of life time of a product) - |TRADABLE - | - |See [FPML](http://www.fpml.org/) for more examples. - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - accountAttributeJson, - accountAttributeResponseJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), - Some(List(canCreateAccountAttributeAtOneBank)) - ) - - lazy val createAccountAttribute : OBPEndpoint = { - case "banks" :: bankId :: "accounts" :: accountId :: "products" :: productCode :: "attribute" :: Nil JsonPost json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountAttributeJson] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AccountAttributeType.DOUBLE}(2012-04-23), ${AccountAttributeType.STRING}(TAX_NUMBER), ${AccountAttributeType.INTEGER}(123) and ${AccountAttributeType.DATE_WITH_DAY}(2012-04-23)" - accountAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - AccountAttributeType.withName(postedData.`type`) - } - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - (_, callContext) <- NewStyle.function.getBankAccount(BankId(bankId), AccountId(accountId), callContext) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, ApiRole.canCreateAccountAttributeAtOneBank, callContext) - (products, callContext) <-NewStyle.function.getProduct(BankId(bankId), ProductCode(productCode), callContext) - (accountAttribute, callContext) <- NewStyle.function.createOrUpdateAccountAttribute( - BankId(bankId), - AccountId(accountId), - ProductCode(productCode), - None, - postedData.name, - accountAttributeType, - postedData.value, - postedData.product_instance_code, - callContext: Option[CallContext] - ) - } yield { - (createAccountAttributeJson(accountAttribute), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateAccountAttribute, - implementedInApiVersion, - nameOf(updateAccountAttribute), - "PUT", - "/banks/BANK_ID/accounts/ACCOUNT_ID/products/PRODUCT_CODE/attributes/ACCOUNT_ATTRIBUTE_ID", - "Update Account Attribute", - s""" Update Account Attribute - | - |$accountAttributeGeneralInfo - | - |Typical account attributes might be: - | - |ISIN (for International bonds) - |VKN (for German bonds) - |REDCODE (markit short code for credit derivative) - |LOAN_ID (e.g. used for Anacredit reporting) - | - |ISSUE_DATE (When the bond was issued in the market) - |MATURITY_DATE (End of life time of a product) - |TRADABLE - | - |See [FPML](http://www.fpml.org/) for more examples. - | - |${userAuthenticationMessage(true)} - | - |""", - accountAttributeJson, - accountAttributeResponseJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), - Some(List(canUpdateAccountAttribute)) - ) - - lazy val updateAccountAttribute : OBPEndpoint = { - case "banks" :: bankId :: "accounts" :: accountId :: "products" :: productCode :: "attributes" :: accountAttributeId :: Nil JsonPut json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - _ <- NewStyle.function.hasEntitlement(bankId, u.userId, canUpdateAccountAttribute, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $AccountAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountAttributeJson] - } - - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AccountAttributeType.DOUBLE}(2012-04-23), ${AccountAttributeType.STRING}(TAX_NUMBER), ${AccountAttributeType.INTEGER}(123) and ${AccountAttributeType.DATE_WITH_DAY}(2012-04-23)" - accountAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - AccountAttributeType.withName(postedData.`type`) - } - - (_, callContext) <- NewStyle.function.getBankAccount(BankId(bankId), AccountId(accountId), callContext) - (_, callContext) <- NewStyle.function.getProduct(BankId(bankId), ProductCode(productCode), callContext) - (_, callContext) <- NewStyle.function.getAccountAttributeById(accountAttributeId, callContext) - - - (accountAttribute, callContext) <- NewStyle.function.createOrUpdateAccountAttribute( - BankId(bankId), - AccountId(accountId), - ProductCode(productCode), - Some(accountAttributeId), - postedData.name, - accountAttributeType, - postedData.value, - postedData.product_instance_code, - callContext: Option[CallContext] - ) - } yield { - (createAccountAttributeJson(accountAttribute), HttpCode.`201`(callContext)) - } - } - } - - - - - - - - resourceDocs += ResourceDoc( - createProductCollection, - implementedInApiVersion, - nameOf(createProductCollection), - "PUT", - "/banks/BANK_ID/product-collections/COLLECTION_CODE", - "Create Product Collection", - s"""Create or Update a Product Collection at the Bank. - | - |Use Product Collections to create Product "Baskets", "Portfolios", "Indices", "Collections", "Underlyings-lists", "Buckets" etc. etc. - | - |There is a many to many relationship between Products and Product Collections: - | - |* A Product can exist in many Collections - | - |* A Collection can contain many Products. - | - |A collection has collection code, one parent Product and one or more child Products. - | - | - |$productHiearchyAndCollectionNote - - |${userAuthenticationMessage(true) } - | - | - |""", - putProductCollectionsV310, - productCollectionsJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProductCollection, apiTagProduct), - Some(List(canMaintainProductCollection)) - ) - - lazy val createProductCollection: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "product-collections" :: collectionCode :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canMaintainProductCollection, callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutProductCollectionsV310 " - product <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutProductCollectionsV310] - } - (products, callContext) <- NewStyle.function.getProducts(bankId, Nil, callContext) - _ <- Helper.booleanToFuture(ProductNotFoundByProductCode + " {" + (product.parent_product_code :: product.children_product_codes).mkString(", ") + "}", cc=callContext) { - val existingCodes = products.map(_.code.value) - val codes = product.parent_product_code :: product.children_product_codes - codes.forall(i => existingCodes.contains(i)) - } - (productCollection, callContext) <- NewStyle.function.getOrCreateProductCollection( - collectionCode, - List(product.parent_product_code), - callContext - ) - (productCollectionItems, callContext) <- NewStyle.function.getOrCreateProductCollectionItems( - collectionCode, - product.children_product_codes, - callContext - ) - } yield { - (createProductCollectionsJson(productCollection, productCollectionItems), HttpCode.`201`(callContext)) - } - - } - } - - - - - resourceDocs += ResourceDoc( - getProductCollection, - implementedInApiVersion, - nameOf(getProductCollection), - "GET", - "/banks/BANK_ID/product-collections/COLLECTION_CODE", - "Get Product Collection", - s"""Returns information about the financial Product Collection specified by BANK_ID and COLLECTION_CODE: - | - """, - EmptyBody, - productCollectionJsonTreeV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError - ), - List(apiTagProductCollection, apiTagProduct) - ) - - lazy val getProductCollection : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "product-collections" :: collectionCode :: Nil JsonGet _ => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (payload, callContext) <- NewStyle.function.getProductCollectionItemsTree(collectionCode, bankId.value, callContext) - } yield { - (createProductCollectionsTreeJson(payload), HttpCode.`200`(callContext)) - } - } - } - } - - // Delete Branch - private[this] val deleteBranchEntitlementsRequiredForSpecificBank = CanDeleteBranch :: Nil - private[this] val deleteBranchEntitlementsRequiredForAnyBank = CanDeleteBranchAtAnyBank :: Nil - private[this] val deleteBranchEntitlementsRequiredText = UserHasMissingRoles + deleteBranchEntitlementsRequiredForSpecificBank.mkString(" and ") + " entitlements are required OR " + deleteBranchEntitlementsRequiredForAnyBank.mkString(" and ") - - resourceDocs += ResourceDoc( - deleteBranch, - implementedInApiVersion, - nameOf(deleteBranch), - "DELETE", - "/banks/BANK_ID/branches/BRANCH_ID", - "Delete Branch", - s"""Delete Branch from given Bank. - | - |${userAuthenticationMessage(true) } - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InsufficientAuthorisationToDeleteBranch, - UnknownError - ), - List(apiTagBranch), - Some(List(canDeleteBranch,canDeleteBranchAtAnyBank)) - ) - - lazy val deleteBranch: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "branches" :: BranchId(branchId) :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - allowedEntitlements = canDeleteBranch ::canDeleteBranchAtAnyBank:: Nil - allowedEntitlementsTxt = allowedEntitlements.mkString(" or ") - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = UserHasMissingRoles + allowedEntitlementsTxt)(bankId.value, u.userId, allowedEntitlements, callContext) - (branch, callContext) <- NewStyle.function.getBranch(bankId, branchId, callContext) - (result, callContext) <- NewStyle.function.deleteBranch(branch, callContext) - } yield { - (Full(result), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createMeeting, - implementedInApiVersion, - "createMeeting", - "POST", - "/banks/BANK_ID/meetings", - "Create Meeting (video conference/call)", - """Create Meeting: Initiate a video conference/call with the bank. - | - |The Meetings resource contains meta data about video/other conference sessions - | - |provider_id determines the provider of the meeting / video chat service. MUST be url friendly (no spaces). - | - |purpose_id explains the purpose of the chat. onboarding | mortgage | complaint etc. MUST be url friendly (no spaces). - | - |Login is required. - | - |This call is **experimental**. Currently staff_user_id is not set. Further calls will be needed to correctly set this. - """.stripMargin, - createMeetingJsonV310, - meetingJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagMeeting, apiTagCustomer, apiTagExperimental)) - - lazy val createMeeting: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $CreateMeetingJson " - createMeetingJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[CreateMeetingJsonV310] - } - // These following are only for `tokbox` stuff, for now, just ignore it. - // _ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(MeetingApiKeyNotConfigured, 403) - // _ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(MeetingApiSecretNotConfigured, 403) - // u <- cc.user ?~! AuthenticatedUserIsRequired - // _ <- tryo(assert(isValidID(bankId.value)))?~! InvalidBankIdFormat - // (bank, callContext) <- Bank(bankId, Some(cc)) ?~! BankNotFound - // postedData <- tryo {json.extract[CreateMeetingJson]} ?~! InvalidJsonFormat - // now = Calendar.getInstance().getTime() - // sessionId <- tryo{code.opentok.OpenTokUtil.getSession.getSessionId()} - // customerToken <- tryo{code.opentok.OpenTokUtil.generateTokenForPublisher(60)} - // staffToken <- tryo{code.opentok.OpenTokUtil.generateTokenForModerator(60)} - //The following three are just used for Tokbox - sessionId = "" - customerToken ="" - staffToken = "" - - creator = ContactDetails(createMeetingJson.creator.name,createMeetingJson.creator.mobile_phone,createMeetingJson.creator.email_address) - invitees = createMeetingJson.invitees.map( - invitee => - Invitee( - ContactDetails(invitee.contact_details.name, invitee.contact_details.mobile_phone,invitee.contact_details.email_address), - invitee.status)) - (meeting, callContext) <- NewStyle.function.createMeeting( - bank.bankId, - u, - u, - createMeetingJson.provider_id, - createMeetingJson.purpose_id, - createMeetingJson.date, - sessionId, - customerToken, - staffToken, - creator, - invitees, - callContext - ) - } yield { - (JSONFactory310.createMeetingJson(meeting), HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getMeetings, - implementedInApiVersion, - "getMeetings", - "GET", - "/banks/BANK_ID/meetings", - "Get Meetings", - """Meetings contain meta data about, and are used to facilitate, video conferences / chats etc. - | - |The actual conference/chats are handled by external services. - | - |Login is required. - | - |This call is **experimental** and will require further authorisation in the future. - """.stripMargin, - EmptyBody, - meetingsJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError), - List(apiTagMeeting, apiTagCustomer, apiTagExperimental)) - - lazy val getMeetings: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - (meetings, callContext) <- NewStyle.function.getMeetings(bank.bankId, u, callContext) - } yield { - (createMeetingsJson(meetings), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getMeeting, - implementedInApiVersion, - "getMeeting", - "GET", - "/banks/BANK_ID/meetings/MEETING_ID", - "Get Meeting", - """Get Meeting specified by BANK_ID / MEETING_ID - |Meetings contain meta data about, and are used to facilitate, video conferences / chats etc. - | - |The actual conference/chats are handled by external services. - | - |Login is required. - | - |This call is **experimental** and will require further authorisation in the future. - """.stripMargin, - EmptyBody, - meetingJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - MeetingNotFound, - UnknownError - ), - List(apiTagMeeting, apiTagCustomer, apiTagExperimental)) - - lazy val getMeeting: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "meetings" :: meetingId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - (meeting, callContext) <- NewStyle.function.getMeeting(bank.bankId, u, meetingId, callContext) - } yield { - (JSONFactory310.createMeetingJson(meeting), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getServerJWK, - implementedInApiVersion, - "getServerJWK", - "GET", - "/certs", - "Get JSON Web Key (JWK)", - """Get the server's public JSON Web Key (JWK) set and certificate chain. - | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects. - | - """.stripMargin, - EmptyBody, - severJWK, - List( - UnknownError - ), - List(apiTagApi, apiTagPSD2AIS, apiTagPsd2)) - - lazy val getServerJWK: OBPEndpoint = { - case "certs" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- anonymousAccess(cc) - } yield { - (parse(CertificateUtil.convertRSAPublicKeyToAnRSAJWK()), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getMessageDocsSwagger, - implementedInApiVersion, - nameOf(getMessageDocsSwagger), - "GET", - "/message-docs/CONNECTOR/swagger2.0", - "Get Message Docs Swagger", - """ - |This endpoint provides example message docs in swagger format. - |It is only relavent for REST Connectors. - | - |This endpoint can be used by the developer building a REST Adapter that connects to the Core Banking System (CBS). - |That is, the Adapter developer can use the Swagger surfaced here to build the REST APIs that the OBP REST connector will call to consume CBS services. - | - |i.e.: - | - |OBP API (Core OBP API code) -> OBP REST Connector (OBP REST Connector code) -> OBP REST Adapter (Adapter developer code) -> CBS (Main Frame) - | - """.stripMargin, - EmptyBody, - EmptyBody, - List(UnknownError), - List(apiTagMessageDoc, apiTagDocumentation, apiTagApi) - ) - - lazy val getMessageDocsSwagger: OBPEndpoint = { - case "message-docs" :: restConnectorVersion ::"swagger2.0" :: Nil JsonGet _ => { - val (resourceDocTags, partialFunctions, locale, contentParam, apiCollectionIdParam) = ResourceDocsAPIMethodsUtil.getParams() - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- anonymousAccess(cc) - cacheKey = APIUtil.createResourceDocCacheKey( - None, - restConnectorVersion, - resourceDocTags, - partialFunctions, - locale, - contentParam, - apiCollectionIdParam, - None - ) - cacheValueFromRedis = Caching.getStaticSwaggerDocCache(cacheKey) - swaggerJValue <- if (cacheValueFromRedis.isDefined) { - NewStyle.function.tryons(s"$UnknownError Can not convert internal swagger file from cache.", 400, cc.callContext) { - json.parse(cacheValueFromRedis.get) - } - } else { - NewStyle.function.tryons(s"$UnknownError Can not convert internal swagger file.", 400, cc.callContext) { - val convertedToResourceDocs = RestConnector_vMar2019.messageDocs.map(toResourceDoc).toList - val resourceDocListFiltered = ResourceDocsAPIMethodsUtil.filterResourceDocs(convertedToResourceDocs, resourceDocTags, partialFunctions) - val resourceDocJsonList = JSONFactory1_4_0.createResourceDocsJson(resourceDocListFiltered, true, None).resource_docs - val swaggerResourceDoc = SwaggerJSONFactory.createSwaggerResourceDoc(resourceDocJsonList, ApiVersion.v3_1_0) - //For this connector swagger, it shares some basic fields with api swagger, eg: BankId, AccountId. So it need to merge here. - val allSwaggerDefinitionCaseClasses = MessageDocsSwaggerDefinitions.allFields ++ SwaggerDefinitionsJSON.allFields - val jsonAST = SwaggerJSONFactory.loadDefinitions(resourceDocJsonList, allSwaggerDefinitionCaseClasses) - val swaggerDocJsonJValue = Extraction.decompose(swaggerResourceDoc) merge jsonAST - val jsonString = json.compactRender(swaggerDocJsonJValue) - Caching.setStaticSwaggerDocCache(cacheKey, jsonString) - swaggerDocJsonJValue - } - } - } yield { - // Merge both results and return - (swaggerJValue, HttpCode.`200`(callContext)) - } - } - } - } - - - val generalObpConsentText : String = - s""" - | - |An OBP Consent allows the holder of the Consent to call one or more endpoints. - | - |Consents must be created and authorisied using SCA (Strong Customer Authentication). - | - |That is, Consents can be created by an authorised User via the OBP REST API but they must be confirmed via an out of band (OOB) mechanism such as a code sent to a mobile phone. - | - |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(", ") }. - | - |Each Consent is bound to a consumer i.e. you need to identify yourself over request header value Consumer-Key. - |For example: - |GET /obp/v4.0.0/users/current HTTP/1.1 - |Host: 127.0.0.1:8080 - |Consent-JWT: eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEFueVVzZXIiLCJiYW5rX2lkIjoiIn - |1dLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIzNDc1MDEzZi03YmY5LTQyNj - |EtOWUxYy0xZTdlNWZjZTJlN2UiLCJhdWQiOiI4MTVhMGVmMS00YjZhLTQyMDUtYjExMi1lNDVmZDZmNGQzYWQiLCJuYmYiOjE1ODA3NDE2NjcsIml - |zcyI6Imh0dHA6XC9cLzEyNy4wLjAuMTo4MDgwIiwiZXhwIjoxNTgwNzQ1MjY3LCJpYXQiOjE1ODA3NDE2NjcsImp0aSI6ImJkYzVjZTk5LTE2ZTY - |tNDM4Yi1hNjllLTU3MTAzN2RhMTg3OCIsInZpZXdzIjpbXX0.L3fEEEhdCVr3qnmyRKBBUaIQ7dk1VjiFaEBW8hUNjfg - | - |Consumer-Key: ejznk505d132ryomnhbx1qmtohurbsbb0kijajsk - |cache-control: no-cache - | - |Maximum time to live of the token is specified over props value consents.max_time_to_live. In case isn't defined default value is 3600 seconds. - | - |Example of POST JSON: - |{ - | "everything": false, - | "views": [ - | { - | "bank_id": "GENODEM1GLS", - | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0", - | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}" - | } - | ], - | "entitlements": [ - | { - | "bank_id": "GENODEM1GLS", - | "role_name": "CanGetCustomersAtOneBank" - | } - | ], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - | "email": "eveline@example.com", - | "valid_from": "2020-02-07T08:43:34Z", - | "time_to_live": 3600 - |} - |Please note that only optional fields are: consumer_id, valid_from and time_to_live. - |In case you omit they the default values are used: - |consumer_id = consumer of current user - |valid_from = current time - |time_to_live = consents.max_time_to_live - | - """.stripMargin - - resourceDocs += ResourceDoc( - createConsentEmail, - implementedInApiVersion, - nameOf(createConsentEmail), - "POST", - "/banks/BANK_ID/my/consents/EMAIL", - "Create Consent (EMAIL)", - s""" - | - |This endpoint starts the process of creating a Consent. - | - |The Consent is created in an ${ConsentStatus.INITIATED} state. - | - |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD - |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL". - |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'. - | - |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint. - | - |$generalObpConsentText - | - |${userAuthenticationMessage(true)} - | - |Example 1: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - | "phone_number": "+49 170 1234567" - |} - | - |Please note that consumer_id is optional field - |Example 2: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - | "phone_number": "+49 170 1234567" - |} - | - |Please note if everything=false you need to explicitly specify views and entitlements - |Example 3: - |{ - | "everything": false, - | "views": [ - | { - | "bank_id": "GENODEM1GLS", - | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0", - | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}" - | } - | ], - | "entitlements": [ - | { - | "bank_id": "GENODEM1GLS", - | "role_name": "CanGetCustomersAtOneBank" - | } - | ], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - | "phone_number": "+49 170 1234567" - |} - | - |""", - postConsentEmailJsonV310, - consentJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - ConsentAllowedScaMethods, - RolesAllowedInConsent, - ViewsAllowedInConsent, - ConsumerNotFoundByConsumerId, - ConsumerIsDisabled, - InvalidConnectorResponse, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil) - - resourceDocs += ResourceDoc( - createConsentSms, - implementedInApiVersion, - nameOf(createConsentSms), - "POST", - "/banks/BANK_ID/my/consents/SMS", - "Create Consent (SMS)", - s""" - | - |This endpoint starts the process of creating a Consent. - | - |The Consent is created in an ${ConsentStatus.INITIATED} state. - | - |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD - |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL". - |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'. - | - |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint. - | - |$generalObpConsentText - | - |${userAuthenticationMessage(true)} - | - |Example 1: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - | "email": "eveline@example.com" - |} - | - |Please note that consumer_id is optional field - |Example 2: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - | "email": "eveline@example.com" - |} - | - |Please note if everything=false you need to explicitly specify views and entitlements - |Example 3: - |{ - | "everything": false, - | "views": [ - | { - | "bank_id": "GENODEM1GLS", - | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0", - | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}" - | } - | ], - | "entitlements": [ - | { - | "bank_id": "GENODEM1GLS", - | "role_name": "CanGetCustomersAtOneBank" - | } - | ], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - | "email": "eveline@example.com" - |} - | - |""", - postConsentPhoneJsonV310, - consentJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - ConsentAllowedScaMethods, - RolesAllowedInConsent, - ViewsAllowedInConsent, - ConsumerNotFoundByConsumerId, - ConsumerIsDisabled, - MissingPropsValueAtThisInstance, - SmsServerNotResponding, - InvalidConnectorResponse, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil) - - resourceDocs += ResourceDoc( - createConsentImplicit, - implementedInApiVersion, - nameOf(createConsentImplicit), - "POST", - "/banks/BANK_ID/my/consents/IMPLICIT", - "Create Consent (IMPLICIT)", - s""" - | - |This endpoint starts the process of creating a Consent. - | - |The Consent is created in an ${ConsentStatus.INITIATED} state. - | - |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD - |SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL". - |Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'. - | - |When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint. - | - |$generalObpConsentText - | - |${userAuthenticationMessage(true)} - | - |Example 1: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - |} - | - |Please note that consumer_id is optional field - |Example 2: - |{ - | "everything": true, - | "views": [], - | "entitlements": [], - |} - | - |Please note if everything=false you need to explicitly specify views and entitlements - |Example 3: - |{ - | "everything": false, - | "views": [ - | { - | "bank_id": "GENODEM1GLS", - | "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0", - | "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}" - | } - | ], - | "entitlements": [ - | { - | "bank_id": "GENODEM1GLS", - | "role_name": "CanGetCustomersAtOneBank" - | } - | ], - | "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", - |} - | - |""", - postConsentImplicitJsonV310, - consentJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - ConsentAllowedScaMethods, - RolesAllowedInConsent, - ViewsAllowedInConsent, - ConsumerNotFoundByConsumerId, - ConsumerIsDisabled, - MissingPropsValueAtThisInstance, - SmsServerNotResponding, - InvalidConnectorResponse, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil) - - lazy val createConsentEmail = createConsent - lazy val createConsentSms = createConsent - lazy val createConsentImplicit = createConsent - - lazy val createConsent : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "my" :: "consents" :: scaMethod :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){ - List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod) - } - failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson " - consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostConsentBodyCommonJson] - } - maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600) - _ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){ - consentJson.time_to_live match { - case Some(ttl) => ttl <= maxTimeToLive - case _ => true - } - } - requestedEntitlements = consentJson.entitlements - myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId) - _ <- Helper.booleanToFuture(RolesAllowedInConsent, cc=callContext){ - requestedEntitlements.forall( - re => myEntitlements.getOrElse(Nil).exists( - e => e.roleName == re.role_name && e.bankId == re.bank_id - ) - ) - } - requestedViews = consentJson.views - (_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user)) - _ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc=callContext){ - requestedViews.forall( - rv => assignedViews.exists{ - e => - e.view_id == rv.view_id && - e.bank_id == rv.bank_id && - e.account_id == rv.account_id - } - ) - } - (consumerId, applicationText, consumer) <- consentJson.consumer_id match { - case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map { - c => (Some(c.consumerId.get), c.description, Some(c)) - } - case None => Future(None, "Any application", None) - } - - - challengeAnswer = Props.mode match { - case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment - case _ => SecureRandomUtil.numeric() - } - createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None, consumer)) map { - i => connectorEmptyResponse(i, callContext) - } - consentJWT = - Consent.createConsentJWT( - user, - consentJson, - createdConsent.secret, - createdConsent.consentId, - consumerId, - consentJson.valid_from, - consentJson.time_to_live.getOrElse(3600), - None - ) - _ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map { - i => connectorEmptyResponse(i, callContext) - } - validUntil = Helper.calculateValidTo(consentJson.valid_from, consentJson.time_to_live.getOrElse(3600)) - _ <- Future(Consents.consentProvider.vend.setValidUntil(createdConsent.consentId, validUntil)) map { - i => connectorEmptyResponse(i, callContext) - } - //we need to check `skip_consent_sca_for_consumer_id_pairs` props, to see if we really need the SCA flow. - //this is from callContext - grantorConsumerId = callContext.map(_.consumer.toOption.map(_.consumerId.get)).flatten.getOrElse("Unknown") - //this is from json body - granteeConsumerId = consentJson.consumer_id.getOrElse("Unknown") - - shouldSkipConsentScaForConsumerIdPair = APIUtil.skipConsentScaForConsumerIdPairs.contains( - APIUtil.ConsumerIdPair( - grantorConsumerId, - granteeConsumerId - )) - mappedConsent <- if (shouldSkipConsentScaForConsumerIdPair) { - Future{ - MappedConsent.find(By(MappedConsent.mConsentId, createdConsent.consentId)).map(_.mStatus(ConsentStatus.ACCEPTED.toString).saveMe()).head - } - } else { - val challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText" - scaMethod match { - case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email - for{ - failMsg <- Future {s"$InvalidJsonFormat The Json body should be the $PostConsentEmailJsonV310"} - postConsentEmailJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostConsentEmailJsonV310] - } - (status, callContext) <- NewStyle.function.sendCustomerNotification( - StrongCustomerAuthentication.EMAIL, - postConsentEmailJson.email, - Some("OBP Consent Challenge"), - challengeText, - callContext - ) - } yield createdConsent - case v if v == StrongCustomerAuthentication.SMS.toString => - for { - failMsg <- Future { - s"$InvalidJsonFormat The Json body should be the $PostConsentPhoneJsonV310" - } - postConsentPhoneJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostConsentPhoneJsonV310] - } - phoneNumber = postConsentPhoneJson.phone_number - (status, callContext) <- NewStyle.function.sendCustomerNotification( - StrongCustomerAuthentication.SMS, - phoneNumber, - None, - challengeText, - callContext - ) - } yield createdConsent - case v if v == StrongCustomerAuthentication.IMPLICIT.toString => - for { - (consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext) - status <- consentImplicitSCA.scaMethod match { - case v if v == StrongCustomerAuthentication.EMAIL => // Send the email - NewStyle.function.sendCustomerNotification ( - StrongCustomerAuthentication.EMAIL, - consentImplicitSCA.recipient, - Some ("OBP Consent Challenge"), - challengeText, - callContext - ) - case v if v == StrongCustomerAuthentication.SMS => - NewStyle.function.sendCustomerNotification( - StrongCustomerAuthentication.SMS, - consentImplicitSCA.recipient, - None, - challengeText, - callContext - ) - case _ => Future { - "Success" - } - }} yield { - createdConsent - } - case _ =>Future{createdConsent}} - } - } yield { - (ConsentJsonV310(createdConsent.consentId, consentJWT, createdConsent.status), HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - answerConsentChallenge, - implementedInApiVersion, - nameOf(answerConsentChallenge), - "POST", - "/banks/BANK_ID/consents/CONSENT_ID/challenge", - "Answer Consent Challenge", - s""" - | - |$generalObpConsentText - | - | - |This endpoint is used to confirm a Consent previously created. - | - |The User must supply a code that was sent out of band (OOB) for example via an SMS. - | - |${userAuthenticationMessage(true)} - | - |""", - PostConsentChallengeJsonV310(answer = "12345678"), - ConsentChallengeJsonV310( - consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945", - jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4", - status = "INITIATED" - ), - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - InvalidConnectorResponse, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil) - - lazy val answerConsentChallenge : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "consents" :: consentId :: "challenge" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentChallengeJsonV310 " - consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostConsentChallengeJsonV310] - } - consent <- Future(Consents.consentProvider.vend.checkAnswer(consentId, consentJson.answer)) map { - i => connectorEmptyResponse(i, callContext) - } - } yield { - (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getConsents, - implementedInApiVersion, - "getConsents", - "GET", - "/banks/BANK_ID/my/consents", - "Get Consents", - s""" - |This endpoint gets the Consents that the current User created. - | - |${userAuthenticationMessage(true)} - | - |1 limit (for pagination: defaults to 50) eg:limit=200 - | - |2 offset (for pagination: zero index, defaults to 0) eg: offset=10 - | - """.stripMargin, - EmptyBody, - consentsJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError - ), - List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)) - - lazy val getConsents: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - val url = cc.url - val limitParam = APIUtil.getHttpRequestUrlParam(url, "limit") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50) - case _ => 50 - } - val offsetParam = APIUtil.getHttpRequestUrlParam(url, "offset") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0) - case _ => 0 - } - for { - (Full(user), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - rows <- Future { - DoobieConsentQueries.getConsentsByUserAndBank( - userId = user.userId, - bankId = bankId.value, - status = None, - limit = limitParam, - offset = offsetParam, - sortField = "created_date", - sortDirection = "desc" - ) - } - } yield { - val consents = rows.map(r => ConsentJsonV310(r.consentId, r.jwt.getOrElse(""), r.status)) - (ConsentsJsonV310(consents), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - revokeConsent, - implementedInApiVersion, - "revokeConsent", - "GET", - "/banks/BANK_ID/my/consents/CONSENT_ID/revoke", - "Revoke Consent", - s""" - |Revoke Consent for current user specified by CONSENT_ID - | - |There are a few reasons you might need to revoke an application’s access to a user’s account: - | - The user explicitly wishes to revoke the application’s access - | - You as the service provider have determined an application is compromised or malicious, and want to disable it - | - etc. - | - |Please note that this endpoint only supports the case:: "The user explicitly wishes to revoke the application’s access" - | - |OBP as a resource server stores access tokens in a database, then it is relatively easy to revoke some token that belongs to a particular user. - |The status of the token is changed to "REVOKED" so the next time the revoked client makes a request, their token will fail to validate. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - revokedConsentJsonV310, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError - ), - List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2)) - - lazy val revokeConsent: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "my" :: "consents" :: consentId :: "revoke" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map { - unboxFullOrFail(_, callContext, ConsentNotFound) - } - _ <- Helper.booleanToFuture(failMsg = ConsentNotFound, cc=callContext) { - consent.mUserId == user.userId - } - consent <- Future(Consents.consentProvider.vend.revoke(consentId)) map { - i => connectorEmptyResponse(i, callContext) - } - } yield { - (ConsentJsonV310(consent.consentId, consent.jsonWebToken, consent.status), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - createUserAuthContextUpdateRequest, - implementedInApiVersion, - nameOf(createUserAuthContextUpdateRequest), - "POST", - "/banks/BANK_ID/users/current/auth-context-updates/SCA_METHOD", - "Create User Auth Context Update Request", - s"""Create User Auth Context Update Request. - |${userAuthenticationMessage(true)} - | - |A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD - |SCA_METHOD is typically "SMS" or "EMAIL". "EMAIL" is used for testing purposes. - | - |""", - postUserAuthContextJson, - userAuthContextUpdateJson, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - CreateUserAuthContextError, - UnknownError - ), - List(apiTagUser), - None - ) - - lazy val createUserAuthContextUpdateRequest : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: scaMethod :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - _ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanCreateUserAuthContextUpdate, cc=callContext) { - checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- Helper.booleanToFuture(UserAuthContextUpdateRequestAllowedScaMethods, cc=callContext){ - List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod) - } - failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostUserAuthContextJson] - } - (userAuthContextUpdate, callContext) <- NewStyle.function.validateUserAuthContextUpdateRequest(bankId.value, user.userId, postedData.key, postedData.value, scaMethod, callContext) - } yield { - - (JSONFactory310.createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - answerUserAuthContextUpdateChallenge, - implementedInApiVersion, - nameOf(answerUserAuthContextUpdateChallenge), - "POST", - "/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge", - "Answer Auth Context Update Challenge", - s""" - |Answer Auth Context Update Challenge. - |""", - PostUserAuthContextUpdateJsonV310(answer = "12345678"), - userAuthContextUpdateJson, - List( - AuthenticatedUserIsRequired, - BankNotFound, - InvalidJsonFormat, - InvalidConnectorResponse, - UnknownError - ), - apiTagUser :: Nil) - - lazy val answerUserAuthContextUpdateChallenge : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "users" :: "current" ::"auth-context-updates" :: authContextUpdateId :: "challenge" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- authenticatedAccess(cc) - failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextUpdateJsonV310 " - postUserAuthContextUpdateJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostUserAuthContextUpdateJsonV310] - } - (userAuthContextUpdate, callContext) <- NewStyle.function.checkAnswer(authContextUpdateId, postUserAuthContextUpdateJson.answer, callContext) - (user, callContext) <- NewStyle.function.getUserByUserId(userAuthContextUpdate.userId, callContext) - (_, callContext) <- - userAuthContextUpdate.status match { - case status if status == UserAuthContextUpdateStatus.ACCEPTED.toString => - NewStyle.function.createUserAuthContext( - user, - userAuthContextUpdate.key, - userAuthContextUpdate.value, - callContext).map(x => (Some(x._1), x._2)) - case _ => - Future((None, callContext)) - } - (_, callContext) <- - userAuthContextUpdate.key match { - case "CUSTOMER_NUMBER" => - NewStyle.function.getOCreateUserCustomerLink( - bankId, - userAuthContextUpdate.value, // Customer number - user.userId, - callContext - ) - case _ => - Future((None, callContext)) - } - } yield { - (createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - getSystemView, - implementedInApiVersion, - "getSystemView", - "GET", - "/system-views/VIEW_ID", - "Get System View", - s"""Get System View - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - viewJSONV220, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError - ), - List(apiTagSystemView), - Some(List(canGetSystemView)) - ) - - lazy val getSystemView: OBPEndpoint = { - case "system-views" :: viewId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", user.userId, canGetSystemView, callContext) - view <- ViewNewStyle.systemView(ViewId(viewId), callContext) - } yield { - (JSONFactory310.createViewJSON(view), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - createSystemView, - implementedInApiVersion, - nameOf(createSystemView), - "POST", - "/system-views", - "Create System View", - s"""Create a system view - | - | ${userAuthenticationMessage(true)} and the user needs to have access to the $canCreateSystemView entitlement. - | The 'alias' field in the JSON can take one of two values: - | - | * _public_: to use the public alias if there is one specified for the other account. - | * _private_: to use the private alias if there is one specified for the other account. - | - | * _''(empty string)_: to use no alias; the view shows the real name of the other account. - | - | The 'hide_metadata_if_alias_used' field in the JSON can take boolean values. If it is set to `true` and there is an alias on the other account then the other accounts' metadata (like more_info, url, image_url, open_corporates_url, etc.) will be hidden. Otherwise the metadata will be shown. - | - | The 'allowed_actions' field is a list containing the name of the actions allowed on this view, all the actions contained will be set to `true` on the view creation, the rest will be set to `false`. - | - | The 'metadata_view' field determines where metadata (comments, tags, images, where tags) for transactions are stored and retrieved. If set to another view's ID (e.g. 'owner'), metadata added through this view will be shared with all other views that also use the same metadata_view value. If left empty, metadata is stored under this view's own ID and is not shared with other views. - | - | Please note that system views cannot be public. In case you try to set it you will get the error $SystemViewCannotBePublicError - | """, - SwaggerDefinitionsJSON.createSystemViewJsonV300, - viewJsonV300, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagSystemView), - Some(List(canCreateSystemView)) - ) - - lazy val createSystemView : OBPEndpoint = { - //creates a system view - case "system-views" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", user.userId, canCreateSystemView, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $CreateViewJson " - createViewJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[CreateViewJsonV300] - } - //System views can not startwith '_' - _ <- Helper.booleanToFuture(failMsg = InvalidSystemViewFormat+s"Current view_name (${createViewJson.name})", cc = callContext) { - isValidSystemViewName(createViewJson.name) - } - _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=callContext) { - createViewJson.is_public == false - } - view <- ViewNewStyle.createSystemView(createViewJson.toCreateViewJson, callContext) - } yield { - (JSONFactory310.createViewJSON(view), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - deleteSystemView, - implementedInApiVersion, - "deleteSystemView", - "DELETE", - "/system-views/VIEW_ID", - "Delete System View", - "Deletes the system view specified by VIEW_ID", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - BankAccountNotFound, - UnknownError, - "user does not have owner access" - ), - List(apiTagSystemView), - Some(List(canDeleteSystemView)) - ) - - lazy val deleteSystemView: OBPEndpoint = { - //deletes a view on an bank account - case "system-views" :: viewId :: Nil JsonDelete req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", user.userId, canDeleteSystemView, callContext) - _ <- ViewNewStyle.systemView(ViewId(viewId), callContext) - view <- ViewNewStyle.deleteSystemView(ViewId(viewId), callContext) - } yield { - (Full(view), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateSystemView, - implementedInApiVersion, - nameOf(updateSystemView), - "PUT", - "/system-views/VIEW_ID", - "Update System View", - s"""Update an existing view on a bank account - | - |${userAuthenticationMessage(true)} and the user needs to have access to the owner view. - | - |The json sent is the same as during view creation (above), with one difference: the 'name' field - |of a view is not editable (it is only set when a view is created)""", - updateSystemViewJson310, - viewJsonV300, - List( - InvalidJsonFormat, - AuthenticatedUserIsRequired, - BankAccountNotFound, - UnknownError - ), - List(apiTagSystemView), - Some(List(canUpdateSystemView)) - ) - - lazy val updateSystemView : OBPEndpoint = { - //updates a view on a bank account - case "system-views" :: viewId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", user.userId, canUpdateSystemView, callContext) - updateJson <- Future { tryo{json.extract[UpdateViewJSON]} } map { - val msg = s"$InvalidJsonFormat The Json body should be the $UpdateViewJSON " - x => unboxFullOrFail(x, callContext, msg) - } - _ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=callContext) { - updateJson.is_public == false - } - _ <- ViewNewStyle.systemView(ViewId(viewId), callContext) - updatedView <- ViewNewStyle.updateSystemView(ViewId(viewId), updateJson, callContext) - } yield { - (JSONFactory310.createViewJSON(updatedView), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - getOAuth2ServerJWKsURIs, - implementedInApiVersion, - "getOAuth2ServerJWKsURIs", - "GET", - "/jwks-uris", - "Get JSON Web Key (JWK) URIs", - """Get the OAuth2 server's public JSON Web Key (JWK) URIs. - | It is required by client applications to validate ID tokens, self-contained access tokens and other issued objects. - | - """.stripMargin, - EmptyBody, - oAuth2ServerJwksUrisJson, - List( - UnknownError - ), - List(apiTagApi, apiTagOAuth, apiTagOIDC)) - - lazy val getOAuth2ServerJWKsURIs: OBPEndpoint = { - case "jwks-uris" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- anonymousAccess(cc) - } yield { - (getOAuth2ServerJwksUrisJson(), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getMethodRoutings, - implementedInApiVersion, - nameOf(getMethodRoutings), - "GET", - "/management/method_routings", - "Get MethodRoutings", - s"""Get the all MethodRoutings. - | - |Query url parameters: - | - |* method_name: filter with method_name - |* active: if active = true, it will show all the webui_ props. Even if they are set yet, we will return all the default webui_ props - | - |eg: - |${getObpApiRoot}/v3.1.0/management/method_routings?active=true - |${getObpApiRoot}/v3.1.0/management/method_routings?method_name=getBank - | - |""", - EmptyBody, - ListResult( - "method_routings", - (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("method-routing-id")))) - ) - , - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagMethodRouting, apiTagApi), - Some(List(canGetMethodRoutings)) - ) - - - lazy val getMethodRoutings: OBPEndpoint = { - case "management" :: "method_routings":: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetMethodRoutings, callContext) - methodRoutings <- NewStyle.function.getMethodRoutingsByMethodName(req.param("method_name")) - } yield { - val definedMethodRoutings = methodRoutings.sortWith(_.methodName < _.methodName) - val listCommons: List[MethodRoutingCommons] = req.param("active") match { - case Full("true") => (definedMethodRoutings ++ getDefaultMethodRountings ).sortWith(_.methodName < _.methodName) - case _ => definedMethodRoutings - } - (ListResult("method_routings", listCommons.map(_.toJson)), HttpCode.`200`(callContext)) - } - } - } - - /** - * get all default methodRountings, - * @return all default methodRounting#methodName, those just in mapped connector - */ - private def getDefaultMethodRountings = { - - val methodRegex = """method \S+(? methodRegex.matcher(it.toString).matches()) - .filter(_.asMethod.isPublic) - .map(_.asMethod) - .map(it => MethodRoutingCommons( - methodName = it.name.toString, - connectorName = "mapped", - isBankIdExactMatch = false, - bankIdPattern = Some("*"), - parameters= List.empty[MethodRoutingParam], - methodRoutingId = Some(""), - )) - .toList - } - - private val supportedConnectorNames = NewStyle.function.getSupportedConnectorNames().mkString("[", " | ", "]") - resourceDocs += ResourceDoc( - createMethodRouting, - implementedInApiVersion, - nameOf(createMethodRouting), - "POST", - "/management/method_routings", - "Create MethodRouting", - s"""Create a MethodRouting. - | - | - |${userAuthenticationMessage(true)} - | - |Explanation of Fields: - | - |* method_name is required String value, current supported value: $supportedConnectorNames - |* 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 parameters for this method - | - |note and CAVEAT!: - | - |* bank_id_pattern has to be empty for methods that do not take bank_id as a function parameter, otherwise might get empty result - |* methods that aggregate bank objects (e.g. getBankAccountsForUser) have to take any existing method routings for these objects into consideration - |* so if you create e.g. a bank specific method routing for getting an account, make sure that it is also served by endpoints getting ALL accounts for ALL banks - |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+" - | - |If the connector name starts with rest, parameters can contain "outBoundMapping" and "inBoundMapping", convert OutBound and InBound json structure. - |for example: - | outBoundMapping example, convert json from source to target: - |![Snipaste_outBoundMapping](https://user-images.githubusercontent.com/2577334/75248007-33332e00-580e-11ea-8d2a-d1856035fa24.png) - |Build OutBound json value rules: - |1 set cId value with: outboundAdapterCallContext.correlationId value - |2 set bankId value with: concat bankId.value value with string helloworld - |3 set originalJson value with: whole source json, note: the field value expression is $$root - | - | - | inBoundMapping example, convert json from source to target: - |![inBoundMapping](https://user-images.githubusercontent.com/2577334/75248199-a9d02b80-580e-11ea-9238-e073264e9170.png) - |Build InBound json value rules: - |1 and 2 set inboundAdapterCallContext and status value: because field name ends with "$$default", remove "$$default" from field name, not change the value - |3 set fullName value with: concat string full: with result.name value - |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0]. - |""", - MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), - MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), - List(MethodRoutingParam("url", "http://mydomain.com/xxx")), - Some("this-method-routing-Id") - ), - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - InvalidConnectorName, - InvalidConnectorMethodName, - UnknownError - ), - List(apiTagMethodRouting, apiTagApi), - Some(List(canCreateMethodRouting))) - - lazy val createMethodRouting : OBPEndpoint = { - case "management" :: "method_routings" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateMethodRouting, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[MethodRoutingCommons]} " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - val entity = json.extract[MethodRoutingCommons] - entity.bankIdPattern match { - case Some(v) if(StringUtils.isBlank(v) || v.trim == "*") => entity.copy(bankIdPattern = Some(MethodRouting.bankIdPatternMatchAny)) - case v => entity - } - } - _ <-NewStyle.function.tryons(InvalidOutBoundMapping, 400, callContext){ - postedData.getOutBoundMapping - } - _ <-NewStyle.function.tryons(InvalidInBoundMapping, 400, callContext){ - postedData.getInBoundMapping - } - connectorName = postedData.connectorName - methodName = postedData.methodName - _ <- Helper.booleanToFuture(s"$InvalidConnectorName please check connectorName: $connectorName or the connector($connectorName) is not supported for this sandbox. ", failCode=400, cc=callContext) { - NewStyle.function.getConnectorByName(connectorName).isDefined - } - _ <- Helper.booleanToFuture(s"$InvalidConnectorMethodName please check methodName: $methodName", failCode=400, cc=callContext) { - //If connectorName = "internal", it mean the dynamic connector methods. - //all the connector method may not be existing yet. So need to get the method name from `mapped` first. - if(connectorName == "internal") - NewStyle.function.getConnectorMethod("mapped", methodName).isDefined - else - NewStyle.function.getConnectorMethod(connectorName, methodName).isDefined - } - invalidRegexMsg = s"$InvalidBankIdRegex The bankIdPattern is invalid regex, bankIdPatten: ${postedData.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) - } - } - _ <- NewStyle.function.checkMethodRoutingAlreadyExists(postedData, callContext) - Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(postedData) - } yield { - val commonsData: MethodRoutingCommons = methodRouting - (commonsData.toJson, HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateMethodRouting, - implementedInApiVersion, - nameOf(updateMethodRouting), - "PUT", - "/management/method_routings/METHOD_ROUTING_ID", - "Update MethodRouting", - s"""Update a MethodRouting. - | - | - |${userAuthenticationMessage(true)} - | - |Explaination of Fields: - | - |* method_name is required String value, current supported value: $supportedConnectorNames - |* 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+" - | - |If connector name start with rest, parameters can contain "outBoundMapping" and "inBoundMapping", to convert OutBound and InBound json structure. - |for example: - | outBoundMapping example, convert json from source to target: - |![Snipaste_outBoundMapping](https://user-images.githubusercontent.com/2577334/75248007-33332e00-580e-11ea-8d2a-d1856035fa24.png) - |Build OutBound json value rules: - |1 set cId value with: outboundAdapterCallContext.correlationId value - |2 set bankId value with: concat bankId.value value with string helloworld - |3 set originalJson value with: whole source json, note: the field value expression is $$root - | - | - | inBoundMapping example, convert json from source to target: - |![inBoundMapping](https://user-images.githubusercontent.com/2577334/75248199-a9d02b80-580e-11ea-9238-e073264e9170.png) - |Build InBound json value rules: - |1 and 2 set inboundAdapterCallContext and status value: because field name ends with "$$default", remove "$$default" from field name, not change the value - |3 set fullName value with: concat string full: with result.name value - |4 set bankRoutingScheme value: because source value is Array, but target value is not Array, the mapping field name must ends with [0]. - |""", - MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), - MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("this-method-routing-Id")), - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - InvalidConnectorName, - InvalidConnectorMethodName, - UnknownError - ), - List(apiTagMethodRouting, apiTagApi), - Some(List(canUpdateMethodRouting))) - - lazy val updateMethodRouting : OBPEndpoint = { - case "management" :: "method_routings" :: methodRoutingId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canUpdateMethodRouting, callContext) - - failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[MethodRoutingCommons]} " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - val entity = json.extract[MethodRoutingCommons].copy(methodRoutingId = Some(methodRoutingId)) - entity.bankIdPattern match { - case Some(v) if(StringUtils.isBlank(v) || v.trim == "*") => entity.copy(bankIdPattern = Some(MethodRouting.bankIdPatternMatchAny)) - case v => entity - } - } - _ <-NewStyle.function.tryons(InvalidOutBoundMapping, 400, callContext){ - putData.getOutBoundMapping - } - _ <-NewStyle.function.tryons(InvalidInBoundMapping, 400, callContext){ - putData.getInBoundMapping - } - connectorName = putData.connectorName - methodName = putData.methodName - _ <- Helper.booleanToFuture(s"$InvalidConnectorName please check connectorName: $connectorName", failCode=400, cc=callContext) { - NewStyle.function.getConnectorByName(connectorName).isDefined - } - _ <- Helper.booleanToFuture(s"$InvalidConnectorMethodName please check methodName: $methodName", failCode=400, cc=callContext) { - //If connectorName = "internal", it mean the dynamic connector methods. - //all the connector method may not be existing yet. So need to get the method name from `mapped` first. - if(connectorName == "internal") - NewStyle.function.getConnectorMethod("mapped", methodName).isDefined - else - NewStyle.function.getConnectorMethod(connectorName, methodName).isDefined - } - (_, _) <- NewStyle.function.getMethodRoutingById(methodRoutingId, callContext) - - 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(!putData.isBankIdExactMatch && putData.bankIdPattern.isDefined) { - Pattern.compile(putData.bankIdPattern.get) - } - } - - Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(putData) - } yield { - val commonsData: MethodRoutingCommons = methodRouting - (commonsData.toJson, HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - deleteMethodRouting, - implementedInApiVersion, - nameOf(deleteMethodRouting), - "DELETE", - "/management/method_routings/METHOD_ROUTING_ID", - "Delete MethodRouting", - s"""Delete a MethodRouting specified by METHOD_ROUTING_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagMethodRouting, apiTagApi), - Some(List(canDeleteMethodRouting))) - - lazy val deleteMethodRouting : OBPEndpoint = { - case "management" :: "method_routings" :: methodRoutingId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getMethodRoutingById(methodRoutingId, callContext) - _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteMethodRouting, callContext) - deleted: Box[Boolean] <- NewStyle.function.deleteMethodRouting(methodRoutingId) - } yield { - (deleted, HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateCustomerEmail, - implementedInApiVersion, - nameOf(updateCustomerEmail), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/email", - "Update the email of a Customer", - s"""Update an email of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerEmailJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerEmail :: Nil) - ) - - lazy val updateCustomerEmail : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "email" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerEmail, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerEmailJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerEmailJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerScaData( - customerId, - None, - Some(putData.email), - None, - callContext) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateCustomerNumber, - implementedInApiVersion, - nameOf(updateCustomerNumber), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/number", - "Update the number of a Customer", - s"""Update the number of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerNumberJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerNumber :: Nil) - ) - - lazy val updateCustomerNumber : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "number" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerNumber, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerNumberJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerNumberJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - - (customerNumberIsAvalible, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, putData.customer_number, callContext) - //There should not be a customer for this number, If there is, then we throw the exception. - _ <- Helper.booleanToFuture(failMsg= s"$CustomerNumberAlreadyExists Current customer_number(${putData.customer_number}) and Current bank_id(${bankId.value})", cc=callContext) {customerNumberIsAvalible} - - (customer, callContext) <- NewStyle.function.updateCustomerScaData( - customerId, - None, - None, - Some(putData.customer_number), - callContext) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateCustomerMobileNumber, - implementedInApiVersion, - nameOf(updateCustomerMobileNumber), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/mobile-number", - "Update the mobile number of a Customer", - s"""Update the mobile number of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerMobileNumberJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerMobilePhoneNumber :: Nil) - ) - - lazy val updateCustomerMobileNumber : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "mobile-number" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerMobilePhoneNumber, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerMobilePhoneNumberJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerMobilePhoneNumberJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerScaData( - customerId, - Some(putData.mobile_phone_number), - None, - None, - callContext) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateCustomerIdentity, - implementedInApiVersion, - nameOf(updateCustomerIdentity), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/identity", - "Update the identity data of a Customer", - s"""Update the identity data of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerIdentityJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerIdentity :: Nil) - ) - lazy val updateCustomerIdentity : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "identity" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerIdentity, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerIdentityJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerIdentityJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerGeneralData( - customerId, - Some(putData.legal_name), - None, - Some(putData.date_of_birth), - None, - None, - None, - None, - Some(putData.title), - None, - Some(putData.name_suffix), - None, - None, - callContext - ) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateCustomerCreditLimit, - implementedInApiVersion, - nameOf(updateCustomerCreditLimit), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/credit-limit", - "Update the credit limit of a Customer", - s"""Update the credit limit of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerCreditLimitJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerCreditLimit :: Nil) - ) - - lazy val updateCustomerCreditLimit : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "credit-limit" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerCreditLimit, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerCreditLimitJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerCreditLimitJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerCreditData( - customerId, - None, - None, - Some(putData.credit_limit), - callContext) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateCustomerCreditRatingAndSource, - implementedInApiVersion, - nameOf(updateCustomerCreditRatingAndSource), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/credit-rating-and-source", - "Update the credit rating and source of a Customer", - s"""Update the credit rating and source of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerCreditRatingAndSourceJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerCreditRatingAndSource :: canUpdateCustomerCreditRatingAndSourceAtAnyBank :: Nil) - ) - - lazy val updateCustomerCreditRatingAndSource : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "credit-rating-and-source" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasAtLeastOneEntitlement(bankId.value, u.userId, List(canUpdateCustomerCreditRatingAndSource,canUpdateCustomerCreditRatingAndSourceAtAnyBank), callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerCreditRatingAndSourceJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerCreditRatingAndSourceJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerCreditData( - customerId, - Some(putData.credit_rating), - Some(putData.credit_source), - None, - callContext) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateAccount, - implementedInApiVersion, - nameOf(updateAccount), - "PUT", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID", - "Update Account", - s"""Update the account. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - updateAccountRequestJsonV310, - updateAccountResponseJsonV310, - List(InvalidJsonFormat, AuthenticatedUserIsRequired, UnknownError, BankAccountNotFound), - List(apiTagAccount), - Some(List(canUpdateAccount)) - ) - - lazy val updateAccount : OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateAccount, callContext) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - (bankAccount, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $UpdateAccountRequestJsonV310 " - consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[UpdateAccountRequestJsonV310] - } - _ <- Helper.booleanToFuture(s"$UpdateBankAccountException Duplication detected in account routings, please specify only one value per routing scheme", cc=callContext){ - consentJson.account_routings.map(_.scheme).distinct.size == consentJson.account_routings.size - } - alreadyExistAccountRoutings <- Future.sequence(consentJson.account_routings.map(accountRouting => - NewStyle.function.getAccountRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext) - .map { - // If we find an already existing account routing linked to the account, it just mean we don't want to update it - case bankAccount if !(bankAccount._1.bankId == bankId && bankAccount._1.accountId == accountId) => Some(accountRouting) - case _ => None - } fallbackTo Future.successful(None) - )) - alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect { - case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" - } - _ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", cc=callContext) { - alreadyExistingAccountRouting.isEmpty - } - (bankAccount,callContext) <- NewStyle.function.updateBankAccount( - bankId, - accountId, - consentJson.`type`, - consentJson.label, - consentJson.branch_id, - consentJson.account_routings.map(r => AccountRouting(r.scheme, r.address)), - callContext - ) - } yield { - (JSONFactory310.createUpdateResponseAccountJson(bankAccount), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - addCardForBank, - implementedInApiVersion, - nameOf(addCardForBank), - "POST", - "/management/banks/BANK_ID/cards", - "Create Card", - s"""Create Card at bank specified by BANK_ID . - | - |${userAuthenticationMessage(true)} - |""", - createPhysicalCardJsonV310, - physicalCardJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - AllowedValuesAre, - UnknownError - ), - List(apiTagCard), - Some(List(canCreateCardsForBank))) - lazy val addCardForBank: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - - failMsg = s"$InvalidJsonFormat The Json body should be the $CreatePhysicalCardJsonV310 " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {json.extract[CreatePhysicalCardJsonV310]} - - _ <- postJson.allows match { - case List() => Future {true} - case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a))) - } - - failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ") - cardReplacementReason <- NewStyle.function.tryons(failMsg, 400, callContext) { - postJson.replacement match { - case Some(value) => CardReplacementReason.valueOf(value.reason_requested) - case None => CardReplacementReason.valueOf(CardReplacementReason.FIRST.toString) - } - } - - _<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10) - - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canCreateCardsForBank, callContext) - - (_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext) - - (_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext) - - replacement = postJson.replacement match { - case Some(replacement) => - Some(CardReplacementInfo(requestedDate = replacement.requested_date, cardReplacementReason)) - case None => None - } - collected = postJson.collected match { - case Some(collected) => Some(CardCollectionInfo(collected)) - case None => None - } - posted = postJson.posted match { - case Some(posted) => Option(CardPostedInfo(posted)) - case None => None - } - - (card, callContext) <- NewStyle.function.createPhysicalCard( - bankCardNumber=postJson.card_number, - nameOnCard=postJson.name_on_card, - cardType = postJson.card_type, - issueNumber=postJson.issue_number, - serialNumber=postJson.serial_number, - validFrom=postJson.valid_from_date, - expires=postJson.expires_date, - enabled=postJson.enabled, - cancelled=false, - onHotList=false, - technology=postJson.technology, - networks= postJson.networks, - allows= postJson.allows, - accountId= postJson.account_id, - bankId=bankId.value, - replacement = replacement, - pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))), - collected = collected, - posted = posted, - customerId = postJson.customer_id, - cvv = "",//added from v500 - brand = "",//added from v500 - callContext - ) - } yield { - (createPhysicalCardJson(card, u), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updatedCardForBank, - implementedInApiVersion, - nameOf(updatedCardForBank), - "PUT", - "/management/banks/BANK_ID/cards/CARD_ID", - "Update Card", - s"""Update Card at bank specified by CARD_ID . - |${userAuthenticationMessage(true)} - |""", - updatePhysicalCardJsonV310, - physicalCardJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - AllowedValuesAre, - UnknownError - ), - List(apiTagCard), - Some(List(canUpdateCardsForBank))) - lazy val updatedCardForBank: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canUpdateCardsForBank, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $UpdatePhysicalCardJsonV310 " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[UpdatePhysicalCardJsonV310] - } - - _ <- postJson.allows match { - case List() => Future {1} - case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a))) - } - - failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ") - _ <- NewStyle.function.tryons(failMsg, 400, callContext) { - CardReplacementReason.valueOf(postJson.replacement.reason_requested) - } - - _<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10) - - (_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext) - - (card, callContext) <- NewStyle.function.getPhysicalCardForBank(bankId, cardId, callContext) - - (_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext) - - (card, callContext) <- NewStyle.function.updatePhysicalCard( - cardId = cardId, - bankCardNumber=card.bankCardNumber, - cardType = postJson.card_type, - nameOnCard=postJson.name_on_card, - issueNumber=postJson.issue_number, - serialNumber=postJson.serial_number, - validFrom=postJson.valid_from_date, - expires=postJson.expires_date, - enabled=postJson.enabled, - cancelled=false, - onHotList=false, - technology=postJson.technology, - networks= postJson.networks, - allows= postJson.allows, - accountId= postJson.account_id, - bankId=bankId.value, - replacement= Some(CardReplacementInfo(requestedDate = postJson.replacement.requested_date, CardReplacementReason.valueOf(postJson.replacement.reason_requested))), - pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))), - collected= Option(CardCollectionInfo(postJson.collected)), - posted = Option(CardPostedInfo(postJson.posted)), - customerId = postJson.customer_id, - callContext = callContext - ) - } yield { - (createPhysicalCardJson(card, u), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getCardsForBank, - implementedInApiVersion, - nameOf(getCardsForBank), - "GET", - "/management/banks/BANK_ID/cards", - "Get Cards for the specified bank", - s"""Should be able to filter on the following fields - | - |eg:/management/banks/BANK_ID/cards?customer_id=66214b8e-259e-44ad-8868-3eb47be70646&account_id=8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0 - | - |1 customer_id should be valid customer_id, otherwise, it will return an empty card list. - | - |2 account_id should be valid account_id , otherwise, it will return an empty card list. - | - | - |${userAuthenticationMessage(true)}""".stripMargin, - EmptyBody, - physicalCardsJsonV310, - List(AuthenticatedUserIsRequired,BankNotFound, UnknownError), - List(apiTagCard)) - lazy val getCardsForBank : OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonGet _ => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetCardsForBank, callContext) - (bank, callContext) <- NewStyle.function.getBank(bankId, callContext) - (cards,callContext) <- NewStyle.function.getPhysicalCardsForBank(bank, u, obpQueryParams, callContext) - } yield { - (createPhysicalCardsJson(cards, u), HttpCode.`200`(callContext)) - } - } - } - } - - resourceDocs += ResourceDoc( - getCardForBank, - implementedInApiVersion, - nameOf(getCardForBank), - "GET", - "/management/banks/BANK_ID/cards/CARD_ID", - "Get Card By Id", - s""" - |This will the datails of the card. - |It shows the account infomation which linked the the card. - |Also shows the card attributes of the card. - | - """.stripMargin, - EmptyBody, - physicalCardWithAttributesJsonV310, - List(AuthenticatedUserIsRequired,BankNotFound, UnknownError), - List(apiTagCard), - Some(List(canGetCardsForBank))) - lazy val getCardForBank : OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonGet _ => { - cc => { - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canGetCardsForBank, callContext) - (_, callContext)<- NewStyle.function.getBank(bankId, callContext) - (card, callContext) <- NewStyle.function.getPhysicalCardForBank(bankId, cardId, callContext) - (cardAttributes, callContext) <- NewStyle.function.getCardAttributesFromProvider(cardId, callContext) - } yield { - val views: List[View] = Views.views.vend.assignedViewsForAccount(BankIdAccountId(card.account.bankId, card.account.accountId)) - val commonsData: List[CardAttributeCommons]= cardAttributes - (createPhysicalCardWithAttributesJson(card, commonsData, u, views), HttpCode.`200`(callContext)) - } - } - } - } - - resourceDocs += ResourceDoc( - deleteCardForBank, - implementedInApiVersion, - nameOf(deleteCardForBank), - "DELETE", - "/management/banks/BANK_ID/cards/CARD_ID", - "Delete Card", - s"""Delete a Card at bank specified by CARD_ID . - | - |${userAuthenticationMessage(true)} - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - AllowedValuesAre, - UnknownError - ), - List(apiTagCard), - Some(List(canCreateCardsForBank))) - lazy val deleteCardForBank: OBPEndpoint = { - case "management"::"banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, ApiRole.canDeleteCardsForBank, callContext) - (bank, callContext) <- NewStyle.function.getBank(bankId, Some(cc)) - (result, callContext) <- NewStyle.function.deletePhysicalCardForBank(bankId, cardId, callContext) - } yield { - (Full(result), HttpCode.`204`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createCardAttribute, - implementedInApiVersion, - nameOf(createCardAttribute), - "POST", - "/management/banks/BANK_ID/cards/CARD_ID/attribute", - "Create Card Attribute", - s""" Create Card Attribute - | - |Card Attributes are used to describe a financial Product with a list of typed key value pairs. - | - |Each Card Attribute is linked to its Card by CARD_ID - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - CardAttributeJson( - cardAttributeNameExample.value, - CardAttributeType.DOUBLE.toString, - cardAttributeValueExample.value - ), - CardAttributeCommons( - Some(BankId(bankIdExample.value)), - Some(cardIdExample.value), - Some(cardAttributeIdExample.value), - cardAttributeNameExample.value, - CardAttributeType.DOUBLE, - cardAttributeValueExample.value), - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCard, apiTagCardAttribute, apiTagAttribute)) - - lazy val createCardAttribute : OBPEndpoint = { - case "management"::"banks" :: bankId :: "cards" :: cardId :: "attribute" :: Nil JsonPost json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - (_, callContext) <- NewStyle.function.getPhysicalCardForBank(BankId(bankId), cardId, callContext) - - failMsg = s"$InvalidJsonFormat The Json body should be the $CardAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[CardAttributeJson] - } - - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${CardAttributeType.DOUBLE}(12.1234), ${CardAttributeType.STRING}(TAX_NUMBER), ${CardAttributeType.INTEGER}(123) and ${CardAttributeType.DATE_WITH_DAY}(2012-04-23)" - createCardAttribute <- NewStyle.function.tryons(failMsg, 400, callContext) { - CardAttributeType.withName(postedData.`type`) - } - - (cardAttribute, callContext) <- NewStyle.function.createOrUpdateCardAttribute( - Some(BankId(bankId)), - Some(cardId), - None, - postedData.name, - createCardAttribute, - postedData.value, - callContext: Option[CallContext] - ) - } yield { - val commonsData: CardAttributeCommons = cardAttribute - (commonsData, HttpCode.`201`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - updateCardAttribute, - implementedInApiVersion, - nameOf(updateCardAttribute), - "PUT", - "/management/banks/BANK_ID/cards/CARD_ID/attributes/CARD_ATTRIBUTE_ID", - "Update Card Attribute", - s""" Update Card Attribute - | - |Card Attributes are used to describe a financial Product with a list of typed key value pairs. - | - |Each Card Attribute is linked to its Card by CARD_ID - | - |${userAuthenticationMessage(true)} - | - |""", - CardAttributeJson( - cardAttributeNameExample.value, - CardAttributeType.DOUBLE.toString, - cardAttributeValueExample.value - ), - CardAttributeCommons( - Some(BankId(bankIdExample.value)), - Some(cardIdExample.value), - Some(cardAttributeIdExample.value), - cardAttributeNameExample.value, - CardAttributeType.DOUBLE, - cardAttributeValueExample.value), - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCard, apiTagCardAttribute, apiTagAttribute)) - - lazy val updateCardAttribute : OBPEndpoint = { - case "management"::"banks" :: bankId :: "cards" :: cardId :: "attributes" :: cardAttributeId :: Nil JsonPut json -> _=> { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(BankId(bankId), callContext) - (_, callContext) <- NewStyle.function.getPhysicalCardForBank(BankId(bankId), cardId, callContext) - (_, callContext) <- NewStyle.function.getCardAttributeById(cardAttributeId, callContext) - - failMsg = s"$InvalidJsonFormat The Json body should be the $CardAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[CardAttributeJson] - } - - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${CardAttributeType.DOUBLE}(12.1234), ${CardAttributeType.STRING}(TAX_NUMBER), ${CardAttributeType.INTEGER}(123) and ${CardAttributeType.DATE_WITH_DAY}(2012-04-23)" - createCardAttribute <- NewStyle.function.tryons(failMsg, 400, callContext) { - CardAttributeType.withName(postedData.`type`) - } - - (cardAttribute, callContext) <- NewStyle.function.createOrUpdateCardAttribute( - Some(BankId(bankId)), - Some(cardId), - Some(cardAttributeId), - postedData.name, - createCardAttribute, - postedData.value, - callContext: Option[CallContext] - ) - } yield { - val commonsData: CardAttributeCommons = cardAttribute - (commonsData, HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateCustomerBranch, - implementedInApiVersion, - nameOf(updateCustomerBranch), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/branch", - "Update the Branch of a Customer", - s"""Update the Branch of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putCustomerBranchJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerIdentity :: Nil) - ) - lazy val updateCustomerBranch : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "branch" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerBranch, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerBranchJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerBranchJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerGeneralData( - customerId, - None, - None, - None, - None, - None, - None, - None, - None, - Some(putData.branch_id), - None, - None, - None, - callContext - ) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - updateCustomerData, - implementedInApiVersion, - nameOf(updateCustomerData), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/data", - "Update the other data of a Customer", - s"""Update the other data of the Customer specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - putUpdateCustomerDataJsonV310, - customerJsonV310, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer), - Some(canUpdateCustomerIdentity :: Nil) - ) - lazy val updateCustomerData : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: customerId :: "data" :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canUpdateCustomerData, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the $PutUpdateCustomerDataJsonV310 " - putData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutUpdateCustomerDataJsonV310] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId(customerId, callContext) - (customer, callContext) <- NewStyle.function.updateCustomerGeneralData( - customerId, - None, - Some(CustomerFaceImage(putData.face_image.date, putData.face_image.url)), - None, - Some(putData.relationship_status), - Some(putData.dependants), - Some(putData.highest_education_attained), - Some(putData.employment_status), - None, - None, - None, - None, - None, - callContext - ) - } yield { - (JSONFactory310.createCustomerJson(customer), HttpCode.`200`(callContext)) - } - } - } - - - resourceDocs += ResourceDoc( - createAccount, - implementedInApiVersion, - "createAccount", - "PUT", - "/banks/BANK_ID/accounts/ACCOUNT_ID", - "Create Account", - """Create Account at bank specified by BANK_ID with Id specified by ACCOUNT_ID. - | - |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body. - | - |If the PUT body USER_ID *is* specified, the logged in user must have the Role canCreateAccount. Once created, the Account will be owned by the User specified by USER_ID. - | - |If the PUT body USER_ID is *not* specified, the account will be owned by the logged in User. - | - |The 'product_code' field SHOULD be a product_code from Product. - |If the 'product_code' matches a product_code from Product, account attributes will be created that match the Product Attributes. - | - |Note: The Amount MUST be zero.""".stripMargin, - createAccountRequestJsonV310, - createAccountResponseJsonV310, - List( - InvalidJsonFormat, - BankNotFound, - AuthenticatedUserIsRequired, - InvalidUserId, - InvalidAccountIdFormat, - InvalidBankIdFormat, - UserNotFoundById, - UserHasMissingRoles, - InvalidAccountBalanceAmount, - InvalidAccountInitialBalance, - InitialBalanceMustBeZero, - InvalidAccountBalanceCurrency, - AccountIdAlreadyExists, - UnknownError - ), - List(apiTagAccount,apiTagOnboarding), - Some(List(canCreateAccount)) - ) - - - lazy val createAccount : OBPEndpoint = { - // Create a new account - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: Nil JsonPut json -> _ => { - cc =>{ - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (account, callContext) <- Connector.connector.vend.checkBankAccountExists(bankId, accountId, callContext) - _ <- Helper.booleanToFuture(AccountIdAlreadyExists, cc=callContext){ - account.isEmpty - } - failMsg = s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} " - createAccountJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[CreateAccountRequestJsonV310] - } - loggedInUserId = u.userId - userIdAccountOwner = if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id else loggedInUserId - _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){ - isValidID(accountId.value) - } - _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext){ - isValidID(accountId.value) - } - (postedOrLoggedInUser,callContext) <- NewStyle.function.findByUserId(userIdAccountOwner, callContext) - // User can create account for self or an account for another user if they have CanCreateAccount role - _ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext){ - isValidID(accountId.value) - } - _ <- if (userIdAccountOwner == loggedInUserId) Future.successful(Full(Unit)) - else NewStyle.function.hasEntitlement(bankId.value, loggedInUserId, canCreateAccount, callContext, s"${UserHasMissingRoles} $canCreateAccount or create account for self") - - initialBalanceAsString = createAccountJson.balance.amount - accountType = createAccountJson.product_code - accountLabel = createAccountJson.label - initialBalanceAsNumber <- NewStyle.function.tryons(InvalidAccountInitialBalance, 400, callContext) { - BigDecimal(initialBalanceAsString) - } - _ <- Helper.booleanToFuture(InitialBalanceMustBeZero, cc=callContext){0 == initialBalanceAsNumber} - _ <- Helper.booleanToFuture(InvalidISOCurrencyCode, cc=callContext){isValidCurrencyISOCode(createAccountJson.balance.currency)} - currency = createAccountJson.balance.currency - (_, callContext ) <- NewStyle.function.getBank(bankId, callContext) - _ <- Helper.booleanToFuture(s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", 400, cc=callContext){ - createAccountJson.account_routings.map(_.scheme).distinct.size == createAccountJson.account_routings.size - } - alreadyExistAccountRoutings <- Future.sequence(createAccountJson.account_routings.map(accountRouting => - NewStyle.function.getAccountRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None)) - )) - alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect { - case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" - } - _ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", cc=callContext) { - alreadyExistingAccountRouting.isEmpty - } - (bankAccount,callContext) <- NewStyle.function.createBankAccount( - bankId, - accountId, - accountType, - accountLabel, - currency, - initialBalanceAsNumber, - postedOrLoggedInUser.name, - createAccountJson.branch_id, - createAccountJson.account_routings.map(r => AccountRouting(r.scheme, r.address)), - callContext - ) - (productAttributes, callContext) <- NewStyle.function.getProductAttributesByBankAndCode(bankId, ProductCode(accountType), callContext) - (accountAttributes, callContext) <- NewStyle.function.createAccountAttributes( - bankId, - accountId, - ProductCode(accountType), - productAttributes, - None, - callContext: Option[CallContext] - ) - //1 Create or Update the `Owner` for the new account - //2 Add permission to the user - //3 Set the user as the account holder - _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess(bankId, accountId, postedOrLoggedInUser, callContext) - } yield { - (JSONFactory310.createAccountJSON(userIdAccountOwner, bankAccount, accountAttributes), HttpCode.`201`(callContext)) - } - } - } - } - - - - resourceDocs += ResourceDoc( - getPrivateAccountByIdFull, - implementedInApiVersion, - nameOf(getPrivateAccountByIdFull), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account", - "Get Account by Id (Full)", - """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID): - | - |* Number - |* Owners - |* Type - |* Balance - |* IBAN - |* Available views (sorted by short_name) - | - |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount). - | - |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications. - |This call provides balance and other account information via delegated authentication using OAuth. - | - |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`. - |""".stripMargin, - EmptyBody, - moderatedAccountJSON310, - List(BankNotFound,AccountNotFound,ViewNotFound, UserNoPermissionAccessView, UnknownError), - apiTagAccount :: Nil) - lazy val getPrivateAccountByIdFull : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) - view <- ViewNewStyle.checkViewAccessAndReturnView(viewId, BankIdAccountId(bankId, accountId), Some(u), callContext) - moderatedAccount <- NewStyle.function.moderatedBankAccountCore(account, view, Full(u), callContext) - (accountAttributes, callContext) <- NewStyle.function.getAccountAttributesByAccount( - bankId, - accountId, - callContext: Option[CallContext]) - } yield { - val availableViews = Views.views.vend.privateViewsUserCanAccessForAccount(u, BankIdAccountId(account.bankId, account.accountId)) - val viewsAvailable = availableViews.map(JSONFactory.createViewJSON).sortBy(_.short_name) - (JSONFactory310.createBankAccountJSON(moderatedAccount, viewsAvailable, accountAttributes), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - saveHistoricalTransaction, - implementedInApiVersion, - nameOf(saveHistoricalTransaction), - "POST", - "/management/historical/transactions ", - "Save Historical Transactions ", - s""" - |Import the historical transactions. - | - |The fields bank_id, account_id, counterparty_id in the json body are all optional ones. - |It support transfer money from account to account, account to counterparty and counterparty to counterparty - |Both bank_id + account_id and counterparty_id can identify the account, so OBP only need one of them to make the payment. - |So: - |When you need the account to account, just omit counterparty_id field.eg: - |{ - | "from": { - | "bank_id": "gh.29.uk", - | "account_id": "1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", - | }, - | "to": { - | "bank_id": "gh.29.uk", - | "account_id": "2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", - | }, - | "value": { - | "currency": "GBP", - | "amount": "10" - | }, - | "description": "this is for work", - | "posted": "2017-09-19T02:31:05Z", - | "completed": "2017-09-19T02:31:05Z", - | "type": "SANDBOX_TAN", - | "charge_policy": "SHARED" - |} - | - |When you need the counterparty to counterparty, need to omit bank_id and account_id field.eg: - |{ - | "from": { - | "counterparty_id": "f6392b7d-4218-45ea-b9a7-eaa71c0202f9" - | }, - | "to": { - | "counterparty_id": "26392b7d-4218-45ea-b9a7-eaa71c0202f9" - | }, - | "value": { - | "currency": "GBP", - | "amount": "10" - | }, - | "description": "this is for work", - | "posted": "2017-09-19T02:31:05Z", - | "completed": "2017-09-19T02:31:05Z", - | "type": "SANDBOX_TAN", - | "charge_policy": "SHARED" - |} - | - |or, you can counterparty to account - |{ - | "from": { - | "counterparty_id": "f6392b7d-4218-45ea-b9a7-eaa71c0202f9" - | }, - | "to": { - | "bank_id": "gh.29.uk", - | "account_id": "8ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", - | }, - | "value": { - | "currency": "GBP", - | "amount": "10" - | }, - | "description": "this is for work", - | "posted": "2017-09-19T02:31:05Z", - | "completed": "2017-09-19T02:31:05Z", - | "type": "SANDBOX_TAN", - | "charge_policy": "SHARED" - |} - | - |This call is experimental. - """.stripMargin, - postHistoricalTransactionJson, - postHistoricalTransactionResponseJson, - List( - InvalidJsonFormat, - BankNotFound, - AccountNotFound, - CounterpartyNotFoundByCounterpartyId, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - UnknownError - ), - List(apiTagTransactionRequest), - Some(List(canCreateHistoricalTransaction)) - ) - - - lazy val saveHistoricalTransaction : OBPEndpoint = { - case "management" :: "historical" :: "transactions" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canCreateHistoricalTransaction, callContext) - - // Check the input JSON format, here is just check the common parts of all four types - transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostHistoricalTransactionJson ", 400, callContext) { - json.extract[PostHistoricalTransactionJson] - } - fromAccountPost = transDetailsJson.from - (fromAccount, callContext) <- if (fromAccountPost.bank_id.isDefined && fromAccountPost.account_id.isDefined && fromAccountPost.counterparty_id.isEmpty){ - for{ - (_, callContext) <- NewStyle.function.getBank(BankId(fromAccountPost.bank_id.get), callContext) - (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(BankId(fromAccountPost.bank_id.get), AccountId(fromAccountPost.account_id.get), callContext) - } yield { - (fromAccount, callContext) - } - } else if (fromAccountPost.bank_id.isEmpty && fromAccountPost.account_id.isEmpty && fromAccountPost.counterparty_id.isDefined){ - for { - (fromCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(fromAccountPost.counterparty_id.get), cc.callContext) - (fromAccount, callContext) <- NewStyle.function.getBankAccountFromCounterparty(fromCounterparty, false, callContext) - }yield{ - (fromAccount, callContext) - } - } else { - throw new RuntimeException(s"$InvalidJsonFormat from object should only contain bank_id and account_id or counterparty_id in the post json body.") - } - - - toAccountPost = transDetailsJson.to - (toAccount, callContext) <- if (toAccountPost.bank_id.isDefined && toAccountPost.account_id.isDefined && toAccountPost.counterparty_id.isEmpty){ - for{ - (_, callContext) <- NewStyle.function.getBank(BankId(toAccountPost.bank_id.get), callContext) - (toAccount, callContext) <- NewStyle.function.checkBankAccountExists(BankId(toAccountPost.bank_id.get), AccountId(toAccountPost.account_id.get), callContext) - } yield { - (toAccount, callContext) - } - } else if (toAccountPost.bank_id.isEmpty && toAccountPost.account_id.isEmpty && toAccountPost.counterparty_id.isDefined){ - for { - (toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toAccountPost.counterparty_id.get), cc.callContext) - (toAccount, callContext) <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext) - }yield{ - (toAccount, callContext) - } - } else { - throw new RuntimeException(s"$InvalidJsonFormat to object should only contain bank_id and account_id or counterparty_id in the post json body.") - } - - amountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", 400, callContext) { - BigDecimal(transDetailsJson.value.amount) - } - - _ <- Helper.booleanToFuture(s"${NotPositiveAmount} Current input is: '${amountNumber}'", cc=callContext) { - amountNumber > BigDecimal("0") - } - - posted <- NewStyle.function.tryons(s"$InvalidDateFormat Current `posted` field is ${transDetailsJson.posted}. Please use this format ${DateWithSecondsFormat.toPattern}! ", 400, callContext) { - new SimpleDateFormat(DateWithSeconds).parse(transDetailsJson.posted) - } - - completed <- NewStyle.function.tryons(s"$InvalidDateFormat Current `completed` field is ${transDetailsJson.completed}. Please use this format ${DateWithSecondsFormat.toPattern}! ", 400, callContext) { - new SimpleDateFormat(DateWithSeconds).parse(transDetailsJson.completed) - } - - // Prevent default value for transaction request type (at least). - _ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) { - isValidCurrencyISOCode(transDetailsJson.value.currency) - } - - amountOfMoneyJson = AmountOfMoneyJsonV121(transDetailsJson.value.currency, transDetailsJson.value.amount) - chargePolicy = transDetailsJson.charge_policy - - //There is no constraint for the type at the moment - transactionType = transDetailsJson.`type` - - (transactionId, callContext) <- NewStyle.function.makeHistoricalPayment( - fromAccount, - toAccount, - posted, - completed, - amountNumber, - transDetailsJson.value.currency, - transDetailsJson.description, - transactionType, - chargePolicy, - callContext - ) - } yield { - (JSONFactory310.createPostHistoricalTransactionResponseJson( - transactionId, - fromAccountPost, - toAccountPost, - value= amountOfMoneyJson, - description = transDetailsJson.description, - posted, - completed, - transactionRequestType = transactionType, - chargePolicy =transDetailsJson.charge_policy), HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - getWebUiProps, - implementedInApiVersion, - nameOf(getWebUiProps), - "GET", - "/management/webui_props", - "Get WebUiProps", - s""" - | - |Get WebUiProps - properties that configure the Web UI behavior and appearance. - | - |Properties with names starting with "webui_" can be stored in the database and managed via API. - | - |**Data Sources:** - | - |1. **Explicit WebUiProps (Database)**: Custom values created/updated via the API and stored in the database. - | - |2. **Implicit WebUiProps (Configuration File)**: Default values defined in the `sample.props.template` configuration file. - | - |**Query Parameter:** - | - |* `active` (optional, boolean string, default: "false") - | - If `active=false` or omitted: Returns only explicit props from the database - | - If `active=true`: Returns explicit props + implicit (default) props from configuration file - | - When both sources have the same property name, the database value takes precedence - | - Implicit props are marked with `webUiPropsId = "default"` - | - |**Examples:** - | - |Get only database-stored props: - |${getObpApiRoot}/v3.1.0/management/webui_props - | - |Get database props combined with defaults: - |${getObpApiRoot}/v3.1.0/management/webui_props?active=true - | - |For more details about WebUI Props, including how to set config file defaults and precedence order, see ${Glossary.getGlossaryItemLink("webui_props")}. - | - |""", - EmptyBody, - ListResult( - "webui_props", - (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id")))) - ) - , - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagWebUiProps), - Some(List(canGetWebUiProps)) - ) - - - lazy val getWebUiProps: OBPEndpoint = { - case "management" :: "webui_props":: Nil JsonGet req => { - cc => implicit val ec = EndpointContext(Some(cc)) - val active = ObpS.param("active").getOrElse("false") - for { - (Full(u), callContext) <- authenticatedAccess(cc) - invalidMsg = s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """ - isActived <- NewStyle.function.tryons(invalidMsg, 400, callContext) { - active.toBoolean - } - _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetWebUiProps, callContext) - explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() } - implicitWebUiPropsRemovedDuplicated = if(isActived){ - val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId= Some("default"))) - if(explicitWebUiProps.nonEmpty){ - //get the same name props in the `implicitWebUiProps` - val duplicatedProps : List[WebUiPropsCommons]= explicitWebUiProps.map(explicitWebUiProp => implicitWebUiProps.filter(_.name == explicitWebUiProp.name)).flatten - //remove the depulicated fields from `implicitWebUiProps` - implicitWebUiProps diff duplicatedProps - } - else implicitWebUiProps.distinct - } else { - List.empty[WebUiPropsCommons] - } - } yield { - val listCommons: List[WebUiPropsCommons] = explicitWebUiProps ++ implicitWebUiPropsRemovedDuplicated - (ListResult("webui_props", listCommons), HttpCode.`200`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - createWebUiProps, - implementedInApiVersion, - nameOf(createWebUiProps), - "POST", - "/management/webui_props", - "Create WebUiProps", - s"""Create a WebUiProps. - | - | - |${userAuthenticationMessage(true)} - | - |Explaination of Fields: - | - |* name is required String value - |* value is required String value - | - |The line break and double quotations should do escape, example: - | - |``` - | - |{"name": "webui_some", "value": "this value - |have "line break" and double quotations."} - | - |``` - |should do escape like this: - | - |``` - | - |{"name": "webui_some", "value": "this value\\nhave \\"line break\\" and double quotations."} - | - |``` - | - |Insert image examples: - | - |``` - |// set width=100 and height=50 - |{"name": "webui_some_pic", "value": "here is a picture ![hello](http://somedomain.com/images/pic.png =100x50)"} - | - |// only set height=50 - |{"name": "webui_some_pic", "value": "here is a picture ![hello](http://somedomain.com/images/pic.png =x50)"} - | - |// only width=20% - |{"name": "webui_some_pic", "value": "here is a picture ![hello](http://somedomain.com/images/pic.png =20%x)"} - | - |``` - | - |""", - WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com"), - WebUiPropsCommons( "webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("some-web-ui-props-id")), - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagWebUiProps), - Some(List(canCreateWebUiProps))) - - lazy val createWebUiProps : OBPEndpoint = { - case "management" :: "webui_props" :: Nil JsonPost json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canCreateWebUiProps, callContext) - failMsg = s"$InvalidJsonFormat The Json body should be the ${classOf[WebUiPropsCommons]} " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[WebUiPropsCommons] - } - invalidMsg = s"""$InvalidWebUiProps name must be start with webui_, but current post name is: ${postedData.name} """ - _ <- NewStyle.function.tryons(invalidMsg, 400, callContext) { - require(postedData.name.startsWith("webui_")) - } - Full(webUiProps) <- Future { MappedWebUiPropsProvider.createOrUpdate(postedData) } - } yield { - val commonsData: WebUiPropsCommons = webUiProps - (commonsData, HttpCode.`201`(callContext)) - } - } - } - - resourceDocs += ResourceDoc( - deleteWebUiProps, - implementedInApiVersion, - nameOf(deleteWebUiProps), - "DELETE", - "/management/webui_props/WEB_UI_PROPS_ID", - "Delete WebUiProps", - s"""Delete a WebUiProps specified by WEB_UI_PROPS_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagWebUiProps), - Some(List(canDeleteWebUiProps))) - - lazy val deleteWebUiProps : OBPEndpoint = { - case "management" :: "webui_props" :: webUiPropsId :: Nil JsonDelete _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement("", u.userId, canDeleteWebUiProps, callContext) - deleted <- Future { MappedWebUiPropsProvider.delete(webUiPropsId) } map { - unboxFullOrFail(_, callContext) - } - } yield { - (deleted, HttpCode.`200`(callContext)) - } - } - } - - 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.""", - EmptyBody, - accountBalancesV310Json, - List(UnknownError), - apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - - lazy val getBankAccountsBalances : OBPEndpoint = { - case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u, bankId) - (accountsBalances, callContext)<- BalanceNewStyle.getBankAccountsBalances(availablePrivateAccounts, callContext) - } yield{ - (createBalancesJson(accountsBalances), HttpCode.`200`(callContext)) - } - } - } - - - - resourceDocs += ResourceDoc( - enableDisableConsumers, - implementedInApiVersion, - "enableDisableConsumers", - "PUT", - "/management/consumers/CONSUMER_ID", - "Enable or Disable Consumers", - s"""Enable/Disable a Consumer specified by CONSUMER_ID. - | - |""", - putEnabledJSON, - putEnabledJSON, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagConsumer), - Some(List(canEnableConsumers,canDisableConsumers))) - - - lazy val enableDisableConsumers: OBPEndpoint = { - case "management" :: "consumers" :: consumerId :: Nil JsonPut json -> _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - putData <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) { - json.extract[PutEnabledJSON] - } - _ <- putData.enabled match { - case true => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canEnableConsumers, callContext) - case false => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canDisableConsumers, callContext) - } - consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext) - updatedConsumer <- Future { - Consumers.consumers.vend.updateConsumer(consumer.id.get, None, None, Some(putData.enabled), None, None, None, None, None,None, None, None) ?~! "Cannot update Consumer" - } - } yield { - // Format the data as json - val json = PutEnabledJSON(updatedConsumer.map(_.isActive.get).getOrElse(false)) - // Return - (json, HttpCode.`200`(callContext)) - } - } - } - - } -} +/* + * All v3.1.0 endpoints have been migrated to Http4s310. This trait is retained + * because `with APIMethods310` may still appear in legacy mixin chains. + * The body is intentionally empty — no Lift Dispatch routes, no ResourceDocs, + * no `Implementations310` class. + * + * Use `Http4s310.Implementations3_1_0` directly (or `OBPAPI3_1_0.Implementations3_1_0`, + * which is a re-export) for ResourceDoc / route access in tests. + */ +trait APIMethods310 { self: RestHelper => } object APIMethods310 extends RestHelper with APIMethods310 { - lazy val newStyleEndpoints: List[(String, String)] = Implementations3_1_0.resourceDocs.map { - rd => (rd.partialFunctionName, rd.implementedInApiVersion.toString()) - }.toList + // Re-export so any caller that still imports APIMethods310.Implementations3_1_0 keeps compiling. + val Implementations3_1_0 = Http4s310.Implementations3_1_0 } + +// ─── Original Lift implementation (commented out) ──────────────────────────── +// The original 6065-line Lift implementation is preserved below as comments. +// To view the full implementation history, use: git show HEAD~3:obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala diff --git a/obp-api/src/main/scala/code/api/v3_1_0/Http4s310.scala b/obp-api/src/main/scala/code/api/v3_1_0/Http4s310.scala index 329fe58cf5..82d8fbea4e 100644 --- a/obp-api/src/main/scala/code/api/v3_1_0/Http4s310.scala +++ b/obp-api/src/main/scala/code/api/v3_1_0/Http4s310.scala @@ -3461,6 +3461,59 @@ object Http4s310 { apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil, None, http4sPartialFunction = Some(answerConsentChallenge)) + // ─── getObpConnectorLoopback ───────────────────────────────────────────── + + val getObpConnectorLoopback: HttpRoutes[IO] = HttpRoutes.of[IO] { + case req @ GET -> `prefixPath` / "connector" / "loopback" => + EndpointHelpers.executeAndRespond(req) { cc => + for { + _ <- code.util.Helper.booleanToFuture(code.api.util.ErrorMessages.NotImplemented, failCode = 400, cc = Some(cc)) { false } + } yield EmptyBody + } + } + + resourceDocs += ResourceDoc( + null, implementedInApiVersion, nameOf(getObpConnectorLoopback), "GET", + "/connector/loopback", + "Get Connector Status (Loopback)", + s"""This endpoint makes a call to the Connector to check the backend transport is reachable. (Deprecated) + | + |${userAuthenticationMessage(true)} + | + |""".stripMargin, + EmptyBody, obpApiLoopbackJson, + List(UnknownError), + List(apiTagApi, apiTagOAuth, apiTagOIDC), + http4sPartialFunction = Some(getObpConnectorLoopback)) + + // ─── getMessageDocsSwagger ─────────────────────────────────────────────── + // Real routing is handled by Http4sResourceDocs (wildcard /obp/*/message-docs/{CONNECTOR}/swagger2.0 + // matched before v310Routes in Http4sApp). This stub val exists only so nameOf compiles + // in downstream test files, and the ResourceDoc entry appears in /resource-docs/v3.1.0/obp. + + val getMessageDocsSwagger: HttpRoutes[IO] = HttpRoutes.empty + + resourceDocs += ResourceDoc( + null, implementedInApiVersion, nameOf(getMessageDocsSwagger), "GET", + "/message-docs/CONNECTOR/swagger2.0", + "Get Message Docs Swagger", + """ + |This endpoint provides example message docs in swagger format. + |It is only relavent for REST Connectors. + | + |This endpoint can be used by the developer building a REST Adapter that connects to the Core Banking System (CBS). + |That is, the Adapter developer can use the Swagger surfaced here to build the REST APIs that the OBP REST connector will call to consume CBS services. + | + |i.e.: + | + |OBP API (Core OBP API code) -> OBP REST Connector (OBP REST Connector code) -> OBP REST Adapter (Adapter developer code) -> CBS (Main Frame) + | + """.stripMargin, + EmptyBody, + EmptyBody, + List(UnknownError), + List(apiTagMessageDoc, apiTagDocumentation, apiTagApi)) + // ─── saveHistoricalTransaction (POST) ──────────────────────────────────── val saveHistoricalTransaction: HttpRoutes[IO] = HttpRoutes.of[IO] { @@ -3657,6 +3710,7 @@ object Http4s310 { .orElse(createConsent.run(req)) .orElse(answerConsentChallenge.run(req)) .orElse(saveHistoricalTransaction.run(req)) + .orElse(getObpConnectorLoopback.run(req)) } val allRoutesWithMiddleware: HttpRoutes[IO] = ResourceDocMiddleware.apply(resourceDocs)(allOwnRoutes) 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 fe1b432498..e9a4871743 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 @@ -28,284 +28,38 @@ package code.api.v3_1_0 import scala.language.reflectiveCalls import code.api.OBPRestHelper -import code.api.util.APIUtil.{OBPEndpoint, getAllowedEndpoints} -import com.openbankproject.commons.util.{ApiVersion,ApiVersionStatus} +import code.api.util.APIUtil.OBPEndpoint import code.api.util.VersionedOBPApis -import code.api.v1_3_0.APIMethods130 -import code.api.v1_4_0.APIMethods140 -import code.api.v2_0_0.APIMethods200 -import code.api.v2_1_0.APIMethods210 -import code.api.v2_2_0.APIMethods220 -import code.api.v3_0_0.APIMethods300 -import code.api.v3_0_0.custom.CustomAPIMethods300 +import code.api.v1_2_1.Http4s121 +import code.api.v2_2_0.Http4s220 +import code.api.v3_0_0.OBPAPI3_0_0 import code.util.Helper.MdcLoggable - -import scala.collection.immutable.Nil - - +import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus} /* -This file defines which endpoints from all the versions are available in v3.0.0 +This file defines which endpoints from all the versions are available in v3.1.0. +All v3.1.0 endpoints have been migrated to Http4s310 — this object is retained +only for resource-doc aggregation and the Lift dispatch registry. */ +object OBPAPI3_1_0 extends OBPRestHelper with MdcLoggable with VersionedOBPApis { + val version: ApiVersion = ApiVersion.v3_1_0 + lazy val versionStatus = ApiVersionStatus.STABLE.toString -object OBPAPI3_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 with APIMethods200 with APIMethods210 with APIMethods220 with APIMethods300 with CustomAPIMethods300 with APIMethods310 with MdcLoggable with VersionedOBPApis{ - - val version : ApiVersion = ApiVersion.v3_1_0 - - val versionStatus = ApiVersionStatus.STABLE.toString - - - // Possible Endpoints from 1.2.1 - lazy val endpointsOf1_2_1 = Implementations1_2_1.addCommentForViewOnTransaction :: - Implementations1_2_1.addCounterpartyCorporateLocation:: - Implementations1_2_1.addCounterpartyImageUrl :: - Implementations1_2_1.addCounterpartyMoreInfo :: - Implementations1_2_1.addCounterpartyOpenCorporatesUrl :: - Implementations1_2_1.addCounterpartyPhysicalLocation :: - Implementations1_2_1.addOtherAccountPrivateAlias :: - Implementations1_2_1.addCounterpartyPublicAlias :: - Implementations1_2_1.addCounterpartyUrl :: - Implementations1_2_1.addImageForViewOnTransaction :: - Implementations1_2_1.addPermissionForUserForBankAccountForMultipleViews :: - Implementations1_2_1.addPermissionForUserForBankAccountForOneView :: - Implementations1_2_1.addTagForViewOnTransaction :: - Implementations1_2_1.addTransactionNarrative :: - Implementations1_2_1.addWhereTagForViewOnTransaction :: - // Now in 3.0.0 "allAccountsAllBanks":: -// Implementations1_2_1.bankById :: - // Implementations1_2_1.createViewForBankAccount :: - Implementations1_2_1.deleteCommentForViewOnTransaction :: - Implementations1_2_1.deleteCommentForViewOnTransaction :: - Implementations1_2_1.deleteCounterpartyCorporateLocation :: - Implementations1_2_1.deleteCounterpartyImageUrl :: - Implementations1_2_1.deleteCounterpartyMoreInfo :: - Implementations1_2_1.deleteCounterpartyOpenCorporatesUrl :: - Implementations1_2_1.deleteCounterpartyPhysicalLocation :: - Implementations1_2_1.deleteCounterpartyPrivateAlias :: - Implementations1_2_1.deleteCounterpartyPublicAlias :: - Implementations1_2_1.deleteCounterpartyUrl :: - Implementations1_2_1.deleteImageForViewOnTransaction :: - Implementations1_2_1.deleteTagForViewOnTransaction :: - Implementations1_2_1.deleteTransactionNarrative :: - Implementations1_2_1.deleteViewForBankAccount:: - Implementations1_2_1.deleteWhereTagForViewOnTransaction :: -// Implementations1_2_1.getBanks :: - Implementations1_2_1.getCommentsForViewOnTransaction :: -// Implementations1_2_1.getOtherAccountsForBankAccount :: -// Implementations1_2_1.getOtherAccountByIdForBankAccount :: - Implementations1_2_1.getOtherAccountForTransaction :: - Implementations1_2_1.getOtherAccountMetadata :: - Implementations1_2_1.getOtherAccountPrivateAlias :: - Implementations1_2_1.getCounterpartyPublicAlias :: - Implementations1_2_1.getImagesForViewOnTransaction :: - Implementations1_2_1.getTagsForViewOnTransaction :: - // Implementations1_2_1.getTransactionByIdForBankAccount :: - Implementations1_2_1.getTransactionNarrative :: - //now in V300 - //Implementations1_2_1.getTransactionsForBankAccount :: - //Implementations1_2_1.getViewsForBankAccount :: - Implementations1_2_1.getWhereTagForViewOnTransaction :: - Implementations1_2_1.removePermissionForUserForBankAccountForAllViews :: - Implementations1_2_1.removePermissionForUserForBankAccountForOneView :: - Implementations1_2_1.updateAccountLabel :: - Implementations1_2_1.updateCounterpartyCorporateLocation :: - Implementations1_2_1.updateCounterpartyImageUrl :: - Implementations1_2_1.updateCounterpartyMoreInfo :: - Implementations1_2_1.updateCounterpartyOpenCorporatesUrl :: - Implementations1_2_1.updateCounterpartyPhysicalLocation :: - Implementations1_2_1.updateCounterpartyPrivateAlias :: - Implementations1_2_1.updateCounterpartyPublicAlias :: - Implementations1_2_1.updateCounterpartyUrl :: - Implementations1_2_1.updateTransactionNarrative :: - //Implementations1_2_1.updateViewForBankAccount :: - Implementations1_2_1.updateWhereTagForViewOnTransaction :: - Nil - - - // Possible Endpoints from VERSION 1.3.0 - val endpointsOf1_3_0 = - Implementations1_3_0.getCards :: -// Implementations1_3_0.getCardsForBank :: - Nil - - - // Possible Endpoints from 1.4.0 - val endpointsOf1_4_0 = Implementations1_4_0.getCustomersMessages :: - Implementations1_4_0.addCustomerMessage :: - // Implementations1_4_0.getBranches :: //now in V300 - // Implementations1_4_0.getAtms :: //now in V300 - Implementations1_4_0.getCrmEvents :: - Implementations1_4_0.getTransactionRequestTypes :: - Nil - - - // Possible Endpoints from 2.0.0 - val endpointsOf2_0_0 = //Now in V3.0.0 Implementations2_0_0.allAccountsAllBanks :: - //Now in V3.0.0 Implementations2_0_0.accountById :: - Implementations2_0_0.addEntitlement :: - Implementations2_0_0.addKycCheck :: - Implementations2_0_0.addKycDocument :: - Implementations2_0_0.addKycMedia :: - Implementations2_0_0.addKycStatus :: - Implementations2_0_0.addSocialMediaHandle :: - Implementations2_0_0.getPrivateAccountsAtOneBank :: - //now in V220 - //Implementations2_0_0.createAccount :: -// Implementations2_0_0.createMeeting :: - Implementations2_0_0.createUser :: - Implementations2_0_0.createUserCustomerLinks :: - Implementations2_0_0.deleteEntitlement :: - Implementations2_0_0.elasticSearchMetrics :: - //Implementations2_0_0.elasticSearchWarehouse :: - // Implementations2_0_0.getAllEntitlements :: - //now in V300 Implementations2_0_0.getCoreAccountById :: - //now in V300 Implementations2_0_0.getCoreTransactionsForBankAccount :: - // Implementations2_0_0.getCurrentUser :: - Implementations2_0_0.getEntitlements :: - Implementations2_0_0.getKycChecks :: - Implementations2_0_0.getKycDocuments :: - Implementations2_0_0.getKycMedia :: - Implementations2_0_0.getKycStatuses :: -// Implementations2_0_0.getMeeting :: -// Implementations2_0_0.getMeetings :: - Implementations2_0_0.getPermissionsForBankAccount :: - Implementations2_0_0.getSocialMediaHandles :: - Implementations2_0_0.getTransactionTypes :: - // Implementations2_0_0.getUser :: - //now in V300 Implementations2_0_0.corePrivateAccountsAllBanks :: - //now in V300 Implementations2_0_0.privateAccountsAtOneBank :: - Implementations2_0_0.publicAccountsAllBanks :: - Implementations2_0_0.publicAccountsAtOneBank :: - Nil - - - // Possible Endpoints from 2.1.0 - val endpointsOf2_1_0 = Implementations2_1_0.sandboxDataImport :: - Implementations2_1_0.getTransactionRequestTypesSupportedByBank :: - Implementations2_1_0.createTransactionRequest :: - Implementations2_1_0.answerTransactionRequestChallenge :: - // Implementations2_1_0.getTransactionRequests :: - Implementations2_1_0.getRoles :: - Implementations2_1_0.getEntitlementsByBankAndUser :: - // Implementations2_1_0.getConsumer :: - // Implementations2_1_0.getConsumers :: - // Implementations2_1_0.enableDisableConsumers :: -// Implementations2_1_0.addCardForBank :: - // Implementations2_1_0.getUsers :: - Implementations2_1_0.createTransactionType :: - // Implementations2_1_0.getAtm :: //now in V300 - // Implementations2_1_0.getBranch :: //now in V300 - Implementations2_1_0.updateBranch :: - // Implementations2_1_0.getProduct :: - // Implementations2_1_0.getProducts :: - // Implementations2_1_0.createCustomer :: - Implementations2_1_0.getCustomersForCurrentUserAtBank :: - // Implementations2_1_0.getCustomersForUser :: - Implementations2_1_0.updateConsumerRedirectUrl :: - Implementations2_1_0.getMetrics :: - Nil - - - // Possible Endpoints from 2.1.0 - val endpointsOf2_2_0 = Implementations2_2_0.getCurrentFxRate :: - Implementations2_2_0.createFx :: - Implementations2_2_0.getExplicitCounterpartiesForAccount :: - Implementations2_2_0.getExplicitCounterpartyById :: - Implementations2_2_0.getMessageDocs :: - Implementations2_2_0.createBank :: - // Implementations2_2_0.createAccount :: - //Implementations2_2_0.createAtm :: - //Implementations2_2_0.createProduct :: -// Implementations2_2_0.config :: - Implementations2_2_0.getConnectorMetrics :: - Implementations2_2_0.createCounterparty :: - //Implementations2_2_0.getCustomersForUser :: - //Implementations2_2_0.getCoreTransactionsForBankAccount :: - Nil - - - // Possible Endpoints from 3.0.0 - val endpointsOf3_0_0 = Implementations3_0_0.getCoreTransactionsForBankAccount :: - Implementations3_0_0.getTransactionsForBankAccount :: - // Implementations3_0_0.getPrivateAccountById :: - Implementations3_0_0.getPublicAccountById :: - Implementations3_0_0.getCoreAccountById :: - Implementations3_0_0.getViewsForBankAccount :: - Implementations3_0_0.createViewForBankAccount :: - Implementations3_0_0.updateViewForBankAccount :: - Implementations3_0_0.corePrivateAccountsAllBanks :: - Implementations3_0_0.dataWarehouseSearch :: - Implementations3_0_0.getUser :: - Implementations3_0_0.getUserByUserId :: - Implementations3_0_0.getUserByUsername :: - Implementations3_0_0.getAdapterInfoForBank :: - Implementations3_0_0.createBranch :: - Implementations3_0_0.getBranches :: - Implementations3_0_0.getBranch :: - Implementations3_0_0.createAtm :: - Implementations3_0_0.getAtm :: - Implementations3_0_0.getAtms :: - Implementations3_0_0.getUsers :: - Implementations3_0_0.getCustomersForUser :: - Implementations3_0_0.getCurrentUser :: - Implementations3_0_0.privateAccountsAtOneBank :: - Implementations3_0_0.getPrivateAccountIdsbyBankId :: - Implementations3_0_0.getOtherAccountsForBankAccount :: - Implementations3_0_0.getOtherAccountByIdForBankAccount :: - Implementations3_0_0.addEntitlementRequest :: - Implementations3_0_0.getAllEntitlementRequests :: - Implementations3_0_0.getEntitlementRequests :: - Implementations3_0_0.deleteEntitlementRequest :: - Implementations3_0_0.dataWarehouseStatistics :: - Implementations3_0_0.getEntitlementRequestsForCurrentUser :: - Implementations3_0_0.getFirehoseAccountsAtOneBank :: - Implementations3_0_0.getEntitlementsForCurrentUser :: - Implementations3_0_0.getFirehoseTransactionsForBankAccount :: - Implementations3_0_0.getApiGlossary :: - Implementations3_0_0.getAccountsHeld :: - Implementations3_0_0.getAggregateMetrics :: - Implementations3_0_0.addScope :: - Implementations3_0_0.deleteScope :: - Implementations3_0_0.getScopes :: - Implementations3_0_0.getBanks :: - Implementations3_0_0.bankById :: - Implementations3_0_0.getPermissionForUserForBankAccount :: - Nil - - - // Possible Endpoints from 3.0.0 Custom Folder - val endpointsOfCustom3_0_0 = ImplementationsCustom3_0_0.endpointsOfCustom3_0_0 - - // Possible Endpoints from 3.1.0 - val endpointsOf3_1_0 = getEndpoints(Implementations3_1_0) - - val allResourceDocs = Implementations3_1_0.resourceDocs ++ - Implementations3_0_0.resourceDocs ++ - ImplementationsCustom3_0_0.resourceDocs ++ - Implementations2_2_0.resourceDocs ++ - Implementations2_1_0.resourceDocs ++ - Implementations2_0_0.resourceDocs ++ - Implementations1_4_0.resourceDocs ++ - Implementations1_3_0.resourceDocs ++ - Implementations1_2_1.resourceDocs - - // Filter the possible endpoints by the disabled / enabled Props settings and add them together - val routes : List[OBPEndpoint] = - getAllowedEndpoints(endpointsOf1_2_1, Implementations1_2_1.resourceDocs) ::: - getAllowedEndpoints(endpointsOf1_3_0, Implementations1_3_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf1_4_0, Implementations1_4_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf2_0_0, Implementations2_0_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf2_1_0, Implementations2_1_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf2_2_0, Implementations2_2_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf3_0_0, Implementations3_0_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOfCustom3_0_0, ImplementationsCustom3_0_0.resourceDocs) ::: - getAllowedEndpoints(endpointsOf3_1_0, Implementations3_1_0.resourceDocs) + // Re-exports so callers that still import OBPAPI3_1_0.ImplementationsX keep compiling. + val Implementations3_1_0 = Http4s310.Implementations3_1_0 + val Implementations1_2_1 = Http4s121.Implementations1_2_1 + val Implementations2_2_0 = Http4s220.Implementations2_2_0 + def allResourceDocs = collectResourceDocs( + OBPAPI3_0_0.allResourceDocs, + Http4s310.resourceDocs + ) - // Make them available for use! - registerRoutes(routes, allResourceDocs, apiPrefix) + val routes: List[OBPEndpoint] = Nil - logger.info(s"version $version has been run! There are ${routes.length} routes.") + registerRoutes(routes, allResourceDocs, apiPrefix, true) + logger.info(s"version $version has been run! There are ${routes.length} routes, ${allResourceDocs.length} allResourceDocs.") + // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here. } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 978747ed2a..9d0881799f 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -1,17042 +1,17057 @@ package code.api.v4_0_0 -import scala.language.reflectiveCalls -import code.DynamicData.DynamicData -import code.DynamicEndpoint.DynamicEndpointSwagger -import code.accountattribute.AccountAttributeX -import code.api.Constant._ -import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON -import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _} -import code.api.dynamic.endpoint.helper.practise.{DynamicEndpointCodeGenerator, PractiseEndpoint} -import code.api.dynamic.endpoint.helper.{CompiledObjects, DynamicEndpointHelper} -import code.api.dynamic.entity.helper.DynamicEntityInfo -import code.api.util.APIUtil.{fullBoxOrException, _} -import code.api.util.ApiRole._ -import code.api.util.ApiTag._ -import code.api.util.CommonsEmailWrapper._ -import code.api.util.DynamicUtil.Validation -import code.api.util.ErrorMessages.{BankNotFound, _} -import code.api.util.ExampleValue._ -import code.api.util.FutureUtil.EndpointContext -import code.api.util.Glossary.getGlossaryItem -import code.api.util.NewStyle.HttpCode -import code.api.util.NewStyle.function._ -import code.api.util._ -import code.api.util.migration.Migration -import code.api.util.newstyle.AttributeDefinition._ -import code.api.util.newstyle.Consumer._ -import code.api.util.newstyle.UserCustomerLinkNewStyle.getUserCustomerLinks -import code.api.util.newstyle.{BalanceNewStyle, UserCustomerLinkNewStyle, ViewNewStyle} -import code.api.v1_2_1.{JSONFactory, PostTransactionTagJSON} -import code.api.v1_4_0.JSONFactory1_4_0 -import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0 -import code.api.v2_0_0.{CreateEntitlementJSON, CreateUserCustomerLinkJson, EntitlementJSONs, JSONFactory200} -import code.api.v2_1_0._ -import code.api.v3_0_0.{CreateScopeJson, JSONFactory300} -import code.api.v3_1_0._ -import code.api.v4_0_0.JSONFactory400._ -import code.api.{Constant, JsonResponseException} -import code.apicollection.MappedApiCollectionsProvider -import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider -import code.authtypevalidation.JsonAuthTypeValidation -import code.bankconnectors.LocalMappedConnectorInternal._ -import code.bankconnectors.{Connector, DynamicConnector, InternalConnector, LocalMappedConnectorInternal} -import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody} -import code.consent.{ConsentStatus, Consents, DoobieConsentQueries} -import code.dynamicEntity.DynamicEntityCommons -import code.dynamicMessageDoc.JsonDynamicMessageDoc -import code.dynamicResourceDoc.JsonDynamicResourceDoc -import code.endpointMapping.EndpointMappingCommons -import code.entitlement.Entitlement -import code.loginattempts.LoginAttempt -import code.metadata.counterparties.{Counterparties, MappedCounterparty} -import code.metadata.tags.Tags -import code.model._ -import code.model.dataAccess.{AuthUser, BankAccountCreation} -import code.ratelimiting.RateLimitingDI -import code.scope.Scope -// Removed: import code.snippet.{WebUIPlaceholder, WebUITemplate} - portal pages removed -import code.usercustomerlinks.UserCustomerLink -import code.userlocks.UserLocksProvider -import code.users.Users -import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN, booleanToFuture} -import code.util.{Helper, JsonSchemaUtil} -import code.validation.JsonValidation -import code.views.Views -import code.webhook.{BankAccountNotificationWebhookTrait, SystemAccountNotificationWebhookTrait} -import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue -import com.github.dwickern.macros.NameOf.nameOf -import com.networknt.schema.ValidationMessage -import com.openbankproject.commons.ExecutionContext.Implicits.global -import com.openbankproject.commons.dto.GetProductsParam -import com.openbankproject.commons.model._ -import com.openbankproject.commons.model.enums.DynamicEntityOperation._ -import com.openbankproject.commons.model.enums.TransactionRequestTypes._ -import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _} -import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion} -import deletion._ -import net.liftweb.common._ -import net.liftweb.http.rest.RestHelper -import net.liftweb.json.JsonAST.JValue -import net.liftweb.json.JsonDSL._ -import net.liftweb.json._ -import net.liftweb.util.Helpers.{now, tryo} -import net.liftweb.util.{Helpers, StringHelpers} -import org.apache.commons.lang3.StringUtils - -import java.net.URLEncoder -import java.text.SimpleDateFormat -import java.util -import java.util.{Calendar, Date} -import scala.collection.JavaConverters._ -import scala.collection.immutable.{List, Nil} -import scala.collection.mutable.ArrayBuffer -import scala.concurrent.Future - -trait APIMethods400 extends MdcLoggable { - self: RestHelper => - - val Implementations4_0_0 = new Implementations400() - - // Email template constants (moved from removed WebUITemplate/WebUIPlaceholder snippets) - private val EMAIL_RECIPIENT_PLACEHOLDER = "{{email_recipient}}" - private val ACTIVATE_ACCOUNT_PLACEHOLDER = "{{activate_your_account}}" - private val DEFAULT_EMAIL_TEXT = s"Dear $EMAIL_RECIPIENT_PLACEHOLDER, please activate your account: $ACTIVATE_ACCOUNT_PLACEHOLDER" - private val DEFAULT_EMAIL_HTML = s"

Dear $EMAIL_RECIPIENT_PLACEHOLDER,

Please activate your account: Activate

" - - - class Implementations400 { - - val implementedInApiVersion = ApiVersion.v4_0_0 - - // DRY constants for dynamic entity documentation - private val dynamicEntityNamingExplanation = - """**IMPORTANT: Entity Naming** - |In the examples below, "AgentConversation" and "AgentMessage" are example entity names. You should replace these with your own entity name (e.g., "Event", "Price", "Order", "Invoice"). The entity name you choose will become the API endpoint name and must be a valid identifier.""".stripMargin - - private val dynamicEntityImportantNotes = - """**Important Notes:** - |- **Entity name is your choice**: "AgentConversation", "FooBar", etc. are just examples. Replace with YOUR entity name (e.g., "Event", "Price", "Invoice") - |- **Entity name becomes the endpoint**: If you create an entity called "Invoice", OBP will generate endpoints like `/obp/dynamic-entity/Invoice`, `POST /obp/dynamic-entity/Invoice`, etc. - |- The entity name (e.g., "AgentConversation") MUST be a direct top-level key in the JSON root object - |- Do NOT wrap the entity in an "entity" field - this is a common mistake - |- Do NOT include "entityName" as a separate field - |- The JSON root can contain at most TWO fields: your entity name and optionally "hasPersonalEntity" - |- The "properties" object contains all field definitions - |- Each property must have "type" and "example" fields. The "description" field is optional - |- For boolean fields, the example must be the STRING "true" or "false" (not boolean values) - |- The "hasPersonalEntity" field is optional (defaults to true) and goes at the root level""".stripMargin - - private val dynamicEntityGeneratedTags = - """**Tags Generated for CRUD Endpoints:** - |When you create a dynamic entity, the resulting CRUD endpoints (GET all, GET one, POST, PUT, DELETE) will automatically be tagged with THREE tags: - |1. **Entity-specific tag** - Based on your entity name (e.g., "Piano", "Invoice", "AgentConversation") - |2. **"Dynamic-Entity"** - Groups all dynamic entity endpoints together - |3. **"Dynamic"** - Groups all dynamic endpoints (both entities and endpoints) - | - |These tags help organize and filter endpoints in the API Explorer.""".stripMargin - - private val dynamicEntityPianoExample = - """ - |**Example 3: Piano Entity Demonstrating Different Field Types** - |```json - |{ - | "Piano": { - | "description": "Piano entity with make, year, number of keys, and type", - | "required": ["make", "year", "number_of_keys", "is_grand", "date_purchased", "weight_in_kg"], - | "properties": { - | "make": { - | "type": "string", - | "example": "Steinway" - | }, - | "year": { - | "type": "string", - | "example": "2023" - | }, - | "number_of_keys": { - | "type": "integer", - | "example": 88 - | }, - | "is_grand": { - | "type": "boolean", - | "example": "true" - | }, - | "date_purchased": { - | "type": "DATE_WITH_DAY", - | "example": "2023-06-15" - | }, - | "weight_in_kg": { - | "type": "number", - | "example": 480.5 - | } - | } - | }, - | "hasPersonalEntity": true - |} - |```""".stripMargin - - private val staticResourceDocs = ArrayBuffer[ResourceDoc]() - // createDynamicEntityDoc and updateDynamicEntityDoc are dynamic, So here dynamic create resourceDocs - def resourceDocs = staticResourceDocs ++ ArrayBuffer[ResourceDoc]( - createDynamicEntityDoc, - createBankLevelDynamicEntityDoc, - updateDynamicEntityDoc, - updateBankLevelDynamicEntityDoc, - updateMyDynamicEntityDoc - ) - - val apiRelations = ArrayBuffer[ApiRelation]() - val codeContext = CodeContext(staticResourceDocs, apiRelations) - - staticResourceDocs += ResourceDoc( - getMapperDatabaseInfo, - implementedInApiVersion, - nameOf(getMapperDatabaseInfo), - "GET", - "/database/info", - "Get Mapper Database Info", - s"""Get basic information about the Mapper Database. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - adapterInfoJsonV300, - List($AuthenticatedUserIsRequired, UnknownError), - List(apiTagApi), - Some(List(canGetDatabaseInfo)) - ) - - lazy val getMapperDatabaseInfo: OBPEndpoint = { - case "database" :: "info" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - Future { - ( - Migration.DbFunction.mapperDatabaseInfo, - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getLogoutLink, - implementedInApiVersion, - nameOf( - getLogoutLink - ), // TODO can we get this string from the val two lines above? - "GET", - "/users/current/logout-link", - "Get Logout Link", - s"""Get the Logout Link - | - |${userAuthenticationMessage(true)} - """.stripMargin, - EmptyBody, - logoutLinkV400, - List($AuthenticatedUserIsRequired, UnknownError), - List(apiTagUser) - ) - - lazy val getLogoutLink: OBPEndpoint = { - case "users" :: "current" :: "logout-link" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - Future { - val link = code.api.Constant.HostName + AuthUser.logoutPath.foldLeft( - "" - )(_ + "/" + _) - val logoutLink = LogoutLinkJson(link) - (logoutLink, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - callsLimit, - implementedInApiVersion, - nameOf(callsLimit), - "PUT", - "/management/consumers/CONSUMER_ID/consumer/call-limits", - "Set Rate Limits / Call Limits per Consumer", - s""" - |Set the API rate limits / call limits for a Consumer: - | - |Rate limiting can be set: - | - |Per Second - |Per Minute - |Per Hour - |Per Week - |Per Month - | - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - callLimitPostJsonV400, - callLimitPostJsonV400, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - InvalidConsumerId, - ConsumerNotFoundByConsumerId, - UserHasMissingRoles, - UpdateConsumerError, - UnknownError - ), - List(apiTagConsumer, apiTagRateLimits), - Some(List(canUpdateRateLimits)) - ) - - lazy val callsLimit: OBPEndpoint = { - case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.handleEntitlementsAndScopes( - "", - u.userId, - List(canUpdateRateLimits), - callContext - ) - postJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $CallLimitPostJsonV400 ", - 400, - callContext - ) { - json.extract[CallLimitPostJsonV400] - } - _ <- NewStyle.function.getConsumerByConsumerId( - consumerId, - callContext - ) - rateLimiting <- RateLimitingDI.rateLimiting.vend - .createOrUpdateConsumerCallLimits( - consumerId, - postJson.from_date, - postJson.to_date, - postJson.api_version, - postJson.api_name, - postJson.bank_id, - Some(postJson.per_second_call_limit), - Some(postJson.per_minute_call_limit), - Some(postJson.per_hour_call_limit), - Some(postJson.per_day_call_limit), - Some(postJson.per_week_call_limit), - Some(postJson.per_month_call_limit) - ) map { - unboxFullOrFail(_, callContext, UpdateConsumerError) - } - } yield { - (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBanks, - implementedInApiVersion, - nameOf(getBanks), - "GET", - "/banks", - "Get Banks", - """Get banks on this API instance - |Returns a list of banks supported on this server: - | - |* ID used as parameter in URLs - |* Short and full name of bank - |* Logo URL - |* Website""", - EmptyBody, - banksJSON400, - List(UnknownError), - apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - - lazy val getBanks: OBPEndpoint = { - case "banks" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (banks, callContext) <- NewStyle.function.getBanks(cc.callContext) - } yield { - (JSONFactory400.createBanksJson(banks), HttpCode.`200`(callContext)) - } - - } - } - - staticResourceDocs += ResourceDoc( - getBank, - implementedInApiVersion, - nameOf(getBank), - "GET", - "/banks/BANK_ID", - "Get Bank", - """Get the bank specified by BANK_ID - |Returns information about a single bank specified by BANK_ID including: - | - |* Short and full name of bank - |* Logo URL - |* Website""", - EmptyBody, - bankJson400, - List(UnknownError, BankNotFound), - apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - - lazy val getBank: OBPEndpoint = { - case "banks" :: BankId(bankId) :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (bank, callContext) <- NewStyle.function.getBank( - bankId, - cc.callContext - ) - (attributes, callContext) <- NewStyle.function - .getBankAttributesByBank(bankId, callContext) - } yield ( - JSONFactory400.createBankJSON400(bank, attributes), - HttpCode.`200`(callContext) - ) - } - } - - staticResourceDocs += ResourceDoc( - ibanChecker, - implementedInApiVersion, - nameOf(ibanChecker), - "POST", - "/account/check/scheme/iban", - "Validate and check IBAN", - """Validate and check IBAN for errors - | - |""", - ibanCheckerPostJsonV400, - ibanCheckerJsonV400, - List(UnknownError), - apiTagAccount :: Nil - ) - - lazy val ibanChecker: OBPEndpoint = { - case "account" :: "check" :: "scheme" :: "iban" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(ibanCheckerPostJsonV400))}" - for { - ibanJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[IbanAddress] - } - (ibanChecker, callContext) <- NewStyle.function - .validateAndCheckIbanNumber(ibanJson.address, cc.callContext) - } yield { - ( - JSONFactory400.createIbanCheckerJson(ibanChecker), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getDoubleEntryTransaction, - implementedInApiVersion, - nameOf(getDoubleEntryTransaction), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/double-entry-transaction", - "Get Double Entry Transaction", - s"""Get Double Entry Transaction - | - |This endpoint can be used to see the double entry transactions. It returns the `bank_id`, `account_id` and `transaction_id` - |for the debit end the credit transaction. The other side account can be a settlement account or an OBP account. - | - |The endpoint also provide the `transaction_request` object which contains the `bank_id`, `account_id` and - |`transaction_request_id` of the transaction request at the origin of the transaction. Please note that if none - |transaction request is at the origin of the transaction, the `transaction_request` object will be `null`. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - doubleEntryTransactionJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction), - Some( - List( - canGetDoubleEntryTransactionAtAnyBank, - canGetDoubleEntryTransactionAtOneBank - ) - ) - ) - - lazy val getDoubleEntryTransaction: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transactions" :: TransactionId( - transactionId - ) :: "double-entry-transaction" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - (doubleEntryTransaction, callContext) <- NewStyle.function - .getDoubleEntryBookTransaction( - bankId, - accountId, - transactionId, - callContext - ) - } yield { - ( - JSONFactory400.createDoubleEntryTransactionJson( - doubleEntryTransaction - ), - HttpCode.`200`(callContext) - ) - } - } - } - staticResourceDocs += ResourceDoc( - getBalancingTransaction, - implementedInApiVersion, - nameOf(getBalancingTransaction), - "GET", - "/transactions/TRANSACTION_ID/balancing-transaction", - "Get Balancing Transaction", - s"""Get Balancing Transaction - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - doubleEntryTransactionJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction), - Some(List()) - ) - - lazy val getBalancingTransaction: OBPEndpoint = { - case "transactions" :: TransactionId( - transactionId - ) :: "balancing-transaction" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (doubleEntryTransaction, callContext) <- NewStyle.function - .getBalancingTransaction(transactionId, cc.callContext) - _ <- ViewNewStyle.checkBalancingTransactionAccountAccessAndReturnView( - doubleEntryTransaction, - cc.user, - cc.callContext - ) - } yield { - ( - JSONFactory400.createDoubleEntryTransactionJson( - doubleEntryTransaction - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createSettlementAccount, - implementedInApiVersion, - nameOf(createSettlementAccount), - "POST", - "/banks/BANK_ID/settlement-accounts", - "Create Settlement Account", - s"""Create a new settlement account at a bank. - | - |The created settlement account id will be the concatenation of the payment system and the account currency. - |For examples: SEPA_SETTLEMENT_ACCOUNT_EUR, CARD_SETTLEMENT_ACCOUNT_USD - | - |By default, when you create a new bank, two settlements accounts are created automatically: OBP_DEFAULT_INCOMING_ACCOUNT_ID and OBP_DEFAULT_OUTGOING_ACCOUNT_ID - |Those two accounts have EUR as default currency. - | - |If you want to create default settlement account for a specific currency, you can fill the `payment_system` field with the `DEFAULT` value. - | - |When a transaction is saved in OBP through the mapped connector, OBP-API look for the account to save the double-entry transaction. - |If no OBP account can be found from the counterparty, the double-entry transaction will be saved on a bank settlement account. - |- First, the mapped connector looks for a settlement account specific to the payment system and currency. E.g SEPA_SETTLEMENT_ACCOUNT_EUR. - |- If we don't find any specific settlement account with the payment system, we look for a default settlement account for the counterparty currency. E.g DEFAULT_SETTLEMENT_ACCOUNT_EUR. - |- Else, we select one of the two OBP default settlement accounts (OBP_DEFAULT_INCOMING_ACCOUNT_ID/OBP_DEFAULT_OUTGOING_ACCOUNT_ID) according to the transaction direction. - | - |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID. - | - |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User. - | - |Note: The Amount MUST be zero. - |""".stripMargin, - settlementAccountRequestJson, - settlementAccountResponseJson, - List( - InvalidJsonFormat, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - $BankNotFound, - InvalidAccountInitialBalance, - InitialBalanceMustBeZero, - InvalidISOCurrencyCode, - UnknownError - ), - List(apiTagBank), - Some(List(canCreateSettlementAccountAtOneBank)) - ) - - lazy val createSettlementAccount: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "settlement-accounts" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(settlementAccountRequestJson))}" - for { - createAccountJson <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[SettlementAccountRequestJson] - } - loggedInUserId = cc.userId - userIdAccountOwner = - if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id - else loggedInUserId - (postedOrLoggedInUser, callContext) <- NewStyle.function.findByUserId( - userIdAccountOwner, - cc.callContext - ) - - _ <- - if (userIdAccountOwner == loggedInUserId) - Future.successful(Full(Unit)) - else - NewStyle.function.hasEntitlement( - bankId.value, - loggedInUserId, - canCreateSettlementAccountAtOneBank, - callContext - ) - - initialBalanceAsString = createAccountJson.balance.amount - accountLabel = createAccountJson.label - initialBalanceAsNumber <- NewStyle.function.tryons( - InvalidAccountInitialBalance, - 400, - callContext - ) { - BigDecimal(initialBalanceAsString) - } - _ <- Helper.booleanToFuture( - InitialBalanceMustBeZero, - cc = callContext - ) { 0 == initialBalanceAsNumber } - currency = createAccountJson.balance.currency - _ <- Helper.booleanToFuture( - InvalidISOCurrencyCode, - cc = callContext - ) { APIUtil.isValidCurrencyISOCode(currency) } - - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- Helper.booleanToFuture( - s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", - cc = callContext - ) { - createAccountJson.account_routings - .map(_.scheme) - .distinct - .size == createAccountJson.account_routings.size - } - alreadyExistAccountRoutings <- Future.sequence( - createAccountJson.account_routings.map(accountRouting => - NewStyle.function - .getAccountRouting( - Some(bankId), - accountRouting.scheme, - accountRouting.address, - callContext - ) - .map(_ => Some(accountRouting)) - .fallbackTo(Future.successful(None)) - ) - ) - alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect { - case Some(accountRouting) => - s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" - } - _ <- Helper.booleanToFuture( - s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", - cc = callContext - ) { - alreadyExistingAccountRouting.isEmpty - } - _ <- Helper.booleanToFuture( - s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", - cc = callContext - ) { - createAccountJson.account_routings - .map(_.scheme) - .distinct - .size == createAccountJson.account_routings.size - } - _ <- Helper.booleanToFuture( - s"$InvalidPaymentSystemName Space characters are not allowed.", - cc = callContext - ) { - !createAccountJson.payment_system.contains(" ") - } - accountId = AccountId( - createAccountJson.payment_system.toUpperCase + "_SETTLEMENT_ACCOUNT_" + currency.toUpperCase - ) - (bankAccount, callContext) <- NewStyle.function.createBankAccount( - bankId, - accountId, - "SETTLEMENT", - accountLabel, - currency, - initialBalanceAsNumber, - postedOrLoggedInUser.name, - createAccountJson.branch_id, - createAccountJson.account_routings.map(r => - AccountRouting(r.scheme, r.address) - ), - callContext - ) - accountId = bankAccount.accountId - (productAttributes, callContext) <- NewStyle.function - .getProductAttributesByBankAndCode( - bankId, - ProductCode("SETTLEMENT"), - callContext - ) - (accountAttributes, callContext) <- NewStyle.function - .createAccountAttributes( - bankId, - accountId, - ProductCode("SETTLEMENT"), - productAttributes, - None, - callContext: Option[CallContext] - ) - // 1 Create or Update the `Owner` for the new account - // 2 Add permission to the user - // 3 Set the user as the account holder - _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess( - bankId, - accountId, - postedOrLoggedInUser, - callContext - ) - } yield { - ( - JSONFactory400.createSettlementAccountJson( - userIdAccountOwner, - bankAccount, - accountAttributes - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getSettlementAccounts, - implementedInApiVersion, - nameOf(getSettlementAccounts), - "GET", - "/banks/BANK_ID/settlement-accounts", - "Get Settlement accounts at Bank", - """Get settlement accounts on this API instance - |Returns a list of settlement accounts at this Bank - | - |Note: a settlement account is considered as a bank account. - |So you can update it and add account attributes to it using the regular account endpoints - |""", - EmptyBody, - settlementAccountsJson, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - $BankNotFound, - UnknownError - ), - List(apiTagBank, apiTagPsd2), - Some(List(canGetSettlementAccountAtOneBank)) - ) - - lazy val getSettlementAccounts: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "settlement-accounts" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- NewStyle.function.hasEntitlement( - bankId.value, - cc.userId, - canGetSettlementAccountAtOneBank, - cc.callContext - ) - - (accounts, callContext) <- NewStyle.function - .getBankSettlementAccounts(bankId, cc.callContext) - settlementAccounts <- Future.sequence(accounts.map(account => { - NewStyle.function - .getAccountAttributesByAccount( - bankId, - account.accountId, - callContext - ) - .map(accountAttributes => - JSONFactory400 - .getSettlementAccountJson(account, accountAttributes._1) - ) - })) - } yield { - ( - SettlementAccountsJson(settlementAccounts), - HttpCode.`200`(callContext) - ) - } - - } - } - - // ACCOUNT. (we no longer create a resource doc for the general case) - staticResourceDocs += ResourceDoc( - createTransactionRequestAccount, - implementedInApiVersion, - "createTransactionRequestAccount", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT/transaction-requests", - "Create Transaction Request (ACCOUNT)", - s"""When using ACCOUNT, the payee is set in the request body. - | - |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body. - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyJsonV200, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - // ACCOUNT_OTP. (we no longer create a resource doc for the general case) - staticResourceDocs += ResourceDoc( - createTransactionRequestAccountOtp, - implementedInApiVersion, - "createTransactionRequestAccountOtp", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT_OTP/transaction-requests", - "Create Transaction Request (ACCOUNT_OTP)", - s"""When using ACCOUNT, the payee is set in the request body. - | - |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body. - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyJsonV200, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - // COUNTERPARTY - staticResourceDocs += ResourceDoc( - createTransactionRequestCounterparty, - implementedInApiVersion, - "createTransactionRequestCounterparty", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/COUNTERPARTY/transaction-requests", - "Create Transaction Request (COUNTERPARTY)", - s""" - |$transactionRequestGeneralText - | - |When using a COUNTERPARTY to create a Transaction Request, specify the counterparty_id in the body of the request. - |The routing details of the counterparty will be forwarded to the Core Banking System (CBS) for the transfer. - | - |COUNTERPARTY Transaction Requests are used for Variable Recurring Payments (VRP). Use the following ${Glossary - .getApiExplorerLink( - "endpoint", - "OBPv5.1.0-createVRPConsentRequest" - )} to create a consent for VRPs. - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - """.stripMargin, - transactionRequestBodyCounterpartyJSON, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - // SIMPLE - staticResourceDocs += ResourceDoc( - createTransactionRequestSimple, - implementedInApiVersion, - nameOf(createTransactionRequestSimple), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SIMPLE/transaction-requests", - "Create Transaction Request (SIMPLE)", - s""" - |Special instructions for SIMPLE: - | - |You can transfer money to the Bank Account Number or IBAN directly. - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodySimpleJsonV400, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - // Transaction Request (SEPA) - staticResourceDocs += ResourceDoc( - createTransactionRequestSepa, - implementedInApiVersion, - "createTransactionRequestSepa", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SEPA/transaction-requests", - "Create Transaction Request (SEPA)", - s""" - |Special instructions for SEPA: - | - |When using a SEPA Transaction Request, you specify the IBAN of a Counterparty in the body of the request. - |The routing details (IBAN) of the counterparty will be forwarded to the core banking system for the transfer. - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodySEPAJsonV400, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - staticResourceDocs += ResourceDoc( - createTransactionRequestRefund, - implementedInApiVersion, - nameOf(createTransactionRequestRefund), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/REFUND/transaction-requests", - "Create Transaction Request (REFUND)", - s""" - | - |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded. - | - |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction. - |In the `from` object, you have two choices : - |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API - |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API - | - |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent. - |(This case is not managed by the OBP-API and require an external adapter) - | - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyRefundJsonV400, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - // FREE_FORM. - staticResourceDocs += ResourceDoc( - createTransactionRequestFreeForm, - implementedInApiVersion, - "createTransactionRequestFreeForm", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/FREE_FORM/transaction-requests", - "Create Transaction Request (FREE_FORM)", - s"""$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyFreeFormJSON, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS), - Some(List(canCreateAnyTransactionRequest)) - ) - - staticResourceDocs += ResourceDoc( - createTransactionRequestAgentCashWithDrawal, - implementedInApiVersion, - nameOf(createTransactionRequestAgentCashWithDrawal), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/AGENT_CASH_WITHDRAWAL/transaction-requests", - "Create Transaction Request (AGENT_CASH_WITHDRAWAL)", - s""" - | - |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded. - | - |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction. - |In the `from` object, you have two choices : - |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API - |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API - | - |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent. - |(This case is not managed by the OBP-API and require an external adapter) - | - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyAgentJsonV400, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - lazy val createTransactionRequestAgentCashWithDrawal: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "AGENT_CASH_WITHDRAWAL" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType( - "AGENT_CASH_WITHDRAWAL" - ) - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestAccount: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "ACCOUNT" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("ACCOUNT") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestAccountOtp: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "ACCOUNT_OTP" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("ACCOUNT_OTP") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestSepa: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "SEPA" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("SEPA") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestCounterparty: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "COUNTERPARTY" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("COUNTERPARTY") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestRefund: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "REFUND" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("REFUND") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestFreeForm: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "FREE_FORM" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("FREE_FORM") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - lazy val createTransactionRequestSimple: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - "SIMPLE" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("SIMPLE") - LocalMappedConnectorInternal.createTransactionRequest( - bankId, - accountId, - viewId, - transactionRequestType, - json - ) - } - - staticResourceDocs += ResourceDoc( - createTransactionRequestCard, - implementedInApiVersion, - nameOf(createTransactionRequestCard), - "POST", - "/transaction-request-types/CARD/transaction-requests", - "Create Transaction Request (CARD)", - s""" - | - |When using CARD, the payee is set in the request body . - | - |Money goes into the Counterparty in the request body. - | - |$transactionRequestGeneralText - | - """.stripMargin, - transactionRequestBodyCardJsonV400, - transactionRequestWithChargeJSON400, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - AccountNotFound, - $BankAccountNotFound, - InsufficientAuthorisationToCreateTransactionRequest, - InvalidTransactionRequestType, - InvalidJsonFormat, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - lazy val createTransactionRequestCard: OBPEndpoint = { - case "transaction-request-types" :: "CARD" :: "transaction-requests" :: Nil JsonPost json -> _ => - cc => - implicit val ec = EndpointContext(Some(cc)) - val transactionRequestType = TransactionRequestType("CARD") - LocalMappedConnectorInternal.createTransactionRequest( - BankId(""), - AccountId(""), - ViewId(Constant.SYSTEM_OWNER_VIEW_ID), - transactionRequestType, - json - ) - } - - staticResourceDocs += ResourceDoc( - answerTransactionRequestChallenge, - implementedInApiVersion, - "answerTransactionRequestChallenge", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge", - "Answer Transaction Request Challenge", - s"""In Sandbox mode, any string that can be converted to a positive integer will be accepted as an answer. - | - |This endpoint totally depends on createTransactionRequest, it need get the following data from createTransactionRequest response body. - | - |1)`TRANSACTION_REQUEST_TYPE` : is the same as createTransactionRequest request URL . - | - |2)`TRANSACTION_REQUEST_ID` : is the `id` field in createTransactionRequest response body. - | - |3) `id` : is `challenge.id` field in createTransactionRequest response body. - | - |4) `answer` : must be `123` in case that Strong Customer Authentication method for OTP challenge is dummy. - | For instance: SANDBOX_TAN_OTP_INSTRUCTION_TRANSPORT=dummy - | Possible values are dummy,email and sms - | In CBS mode, the answer can be got by phone message or other SCA methods. - | - |Note that each Transaction Request Type can have its own OTP_INSTRUCTION_TRANSPORT method. - |OTP_INSTRUCTION_TRANSPORT methods are set in Props. See sample.props.template for instructions. - | - |Single or Multiple authorisations - | - |OBP allows single or multi party authorisations. - | - |Single party authorisation: - | - |In the case that only one person needs to authorise i.e. answer a security challenge we have the following change of state of a `transaction request`: - | INITIATED => COMPLETED - | - | - |Multiparty authorisation: - | - |In the case that multiple parties (n persons) need to authorise a transaction request i.e. answer security challenges, we have the followings state flow for a `transaction request`: - | INITIATED => NEXT_CHALLENGE_PENDING => ... => NEXT_CHALLENGE_PENDING => COMPLETED - | - |The security challenge is bound to a user i.e. in the case of a correct answer but the user is different than expected the challenge will fail. - | - |Rule for calculating number of security challenges: - |If Product Account attribute REQUIRED_CHALLENGE_ANSWERS=N then create N challenges - |(one for every user that has a View where permission $CAN_ADD_TRANSACTION_REQUEST_TO_ANY_ACCOUNT=true) - |In the case REQUIRED_CHALLENGE_ANSWERS is not defined as an account attribute, the default number of security challenges created is one. - | - """.stripMargin, - challengeAnswerJson400, - transactionRequestWithChargeJSON210, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - InvalidAccountIdFormat, - InvalidJsonFormat, - $BankNotFound, - $BankAccountNotFound, - TransactionRequestStatusNotInitiated, - TransactionRequestTypeHasChanged, - AllowedAttemptsUsedUp, - TransactionDisabled, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - lazy val answerTransactionRequestChallenge: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-request-types" :: - TransactionRequestType( - transactionRequestType - ) :: "transaction-requests" :: TransactionRequestId( - transReqId - ) :: "challenge" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, fromAccount, callContext) <- SS.userBankAccount - _ <- NewStyle.function.isEnabledTransactionRequests(callContext) - _ <- Helper.booleanToFuture( - InvalidAccountIdFormat, - cc = callContext - ) { - isValidID(accountId.value) - } - _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { - isValidID(bankId.value) - } - challengeAnswerJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $ChallengeAnswerJson400", - 400, - callContext - ) { - json.extract[ChallengeAnswerJson400] - } - - account = BankIdAccountId(fromAccount.bankId, fromAccount.accountId) - _ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest( - viewId, - account, - u, - callContext - ) - - // Check transReqId is valid - (existingTransactionRequest, callContext) <- NewStyle.function - .getTransactionRequestImpl(transReqId, callContext) - - // Check the Transaction Request is still INITIATED or NEXT_CHALLENGE_PENDING or FORWARDED - _ <- Helper.booleanToFuture( - TransactionRequestStatusNotInitiatedOrPendingOrForwarded, - cc = callContext - ) { - existingTransactionRequest.status.equals( - TransactionRequestStatus.INITIATED.toString - ) || - existingTransactionRequest.status.equals( - TransactionRequestStatus.NEXT_CHALLENGE_PENDING.toString - ) || - existingTransactionRequest.status.equals( - TransactionRequestStatus.FORWARDED.toString - ) - } - - // Check Maker/Checker separation if required by the view - _ <- NewStyle.function.checkMakerCheckerForTransactionRequest( - bankId, - accountId, - viewId, - transReqId, - challengeAnswerJson.id, - u.userId, - callContext - ) - - // Check the input transactionRequestType is the same as when the user created the TransactionRequest - existingTransactionRequestType = existingTransactionRequest.`type` - _ <- Helper.booleanToFuture( - s"${TransactionRequestTypeHasChanged} It should be :'$existingTransactionRequestType', but current value (${transactionRequestType.value}) ", - cc = callContext - ) { - existingTransactionRequestType.equals(transactionRequestType.value) - } - - (challenges, callContext) <- NewStyle.function - .getChallengesByTransactionRequestId(transReqId.value, callContext) - - // Check the challenge type, Note: not supported yet, the default value is SANDBOX_TAN - _ <- Helper.booleanToFuture( - s"$InvalidChallengeType Current Type is ${challenges.map(_.challengeType)}", - cc = callContext - ) { - challenges - .map(_.challengeType) - .filterNot(challengeType => - challengeType.equals( - ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE.toString - ) - ) - .isEmpty - } - - (transactionRequest, callContext) <- - challengeAnswerJson.answer match { - // If the challenge answer is `REJECT` - Currently only to Reject a SEPA transaction request REFUND - case "REJECT" => - val transactionRequest = - existingTransactionRequest.copy(status = - TransactionRequestStatus.REJECTED.toString - ) - for { - (fromAccount, toAccount, callContext) <- { - // If the transaction request comes from the account to debit - if ( - fromAccount.accountId.value == transactionRequest.from.account_id - ) { - val toCounterpartyIban = - transactionRequest.other_account_routing_address - for { - (toCounterparty, callContext) <- NewStyle.function - .getCounterpartyByIbanAndBankAccountId( - toCounterpartyIban, - fromAccount.bankId, - fromAccount.accountId, - callContext - ) - (toAccount, callContext) <- NewStyle.function - .getBankAccountFromCounterparty( - toCounterparty, - true, - callContext - ) - } yield (fromAccount, toAccount, callContext) - } else { - // Else, the transaction request debit a counterparty (Iban) - val fromCounterpartyIban = - transactionRequest.from.account_id - // and the creditor is the obp account owner - val toAccount = fromAccount - for { - (fromCounterparty, callContext) <- NewStyle.function - .getCounterpartyByIbanAndBankAccountId( - fromCounterpartyIban, - toAccount.bankId, - toAccount.accountId, - callContext - ) - (fromAccount, callContext) <- NewStyle.function - .getBankAccountFromCounterparty( - fromCounterparty, - false, - callContext - ) - } yield (fromAccount, toAccount, callContext) - } - } - rejectReasonCode = challengeAnswerJson.reason_code.getOrElse( - "" - ) - _ <- - if (rejectReasonCode.nonEmpty) { - NewStyle.function - .createOrUpdateTransactionRequestAttribute( - bankId = bankId, - transactionRequestId = transactionRequest.id, - transactionRequestAttributeId = None, - name = "reject_reason_code", - attributeType = - TransactionRequestAttributeType.withName("STRING"), - value = rejectReasonCode, - callContext = callContext - ) - } else Future.successful(()) - rejectAdditionalInformation = - challengeAnswerJson.additional_information.getOrElse("") - _ <- - if (rejectAdditionalInformation.nonEmpty) { - NewStyle.function - .createOrUpdateTransactionRequestAttribute( - bankId = bankId, - transactionRequestId = transactionRequest.id, - transactionRequestAttributeId = None, - name = "reject_additional_information", - attributeType = - TransactionRequestAttributeType.withName("STRING"), - value = rejectAdditionalInformation, - callContext = callContext - ) - } else Future.successful(()) - _ <- NewStyle.function.notifyTransactionRequest( - fromAccount, - toAccount, - transactionRequest, - callContext - ) - _ <- NewStyle.function.saveTransactionRequestStatusImpl( - transactionRequest.id, - transactionRequest.status, - callContext - ) - } yield (transactionRequest, callContext) - case _ => - // Determine if the current user is answering their own assigned challenge - val challengeToAnswer = challenges.find(_.challengeId == challengeAnswerJson.id) - val isAnsweringOwnChallenge = challengeToAnswer.exists(_.expectedUserId == u.userId) - - for { - - (challengeAnswerIsValidated, callContext) <- if (isAnsweringOwnChallenge) { - // User is answering their own challenge — validate with userId check - NewStyle.function.validateChallengeAnswer( - challengeAnswerJson.id, - challengeAnswerJson.answer, - SuppliedAnswerType.PLAIN_TEXT_VALUE, - callContext - ) - } else { - // User is answering someone else's challenge (checker answering maker's challenge) - // Safe because maker-checker check already approved this user - NewStyle.function.validateChallengeAnswerWithoutUserIdCheck( - challengeAnswerJson.id, - challengeAnswerJson.answer, - SuppliedAnswerType.PLAIN_TEXT_VALUE, - callContext - ) - } - - _ <- Helper.booleanToFuture( - s"${InvalidChallengeAnswer - .replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).") - .replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")}", - cc = callContext - ) { - challengeAnswerIsValidated - } - - (challengeAnswerIsValidated, callContext) <- NewStyle.function - .allChallengesSuccessfullyAnswered( - bankId, - accountId, - transReqId, - callContext - ) - _ <- Helper.booleanToFuture( - s"$NextChallengePending", - cc = callContext - ) { - challengeAnswerIsValidated - } - (transactionRequest, callContext) <- TransactionRequestTypes - .withName(transactionRequestType.value) match { - case TRANSFER_TO_PHONE | TRANSFER_TO_ATM | - TRANSFER_TO_ACCOUNT => - NewStyle.function.createTransactionAfterChallengeV300( - u, - fromAccount, - transReqId, - transactionRequestType, - callContext - ) - case _ => - NewStyle.function.createTransactionAfterChallengeV210( - fromAccount, - existingTransactionRequest, - callContext - ) - } - } yield (transactionRequest, callContext) - } - - (transactionRequestAttribute, callContext) <- NewStyle.function - .getTransactionRequestAttributes( - bankId, - transactionRequest.id, - callContext - ) - } yield { - - ( - JSONFactory400.createTransactionRequestWithChargeJSON( - transactionRequest, - challenges, - transactionRequestAttribute - ), - HttpCode.`202`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createTransactionRequestAttribute, - implementedInApiVersion, - nameOf(createTransactionRequestAttribute), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attribute", - "Create Transaction Request Attribute", - s""" Create Transaction Request Attribute - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - transactionRequestAttributeJsonV400, - transactionRequestAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canCreateTransactionRequestAttributeAtOneBank)) - ) - - lazy val createTransactionRequestAttribute: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transaction-requests" :: TransactionRequestId( - transactionRequestId - ) :: "attribute" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $transactionRequestAttributeJsonV400 " - for { - (_, callContext) <- NewStyle.function.getTransactionRequestImpl( - transactionRequestId, - cc.callContext - ) - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[TransactionRequestAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" - transactionRequestAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - TransactionRequestAttributeType.withName(postedData.attribute_type) - } - (transactionRequestAttribute, callContext) <- NewStyle.function - .createOrUpdateTransactionRequestAttribute( - bankId, - transactionRequestId, - None, - postedData.name, - transactionRequestAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionRequestAttributeJson( - transactionRequestAttribute - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionRequestAttributeById, - implementedInApiVersion, - nameOf(getTransactionRequestAttributeById), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID", - "Get Transaction Request Attribute By Id", - s""" Get Transaction Request Attribute By Id - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionRequestAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canGetTransactionRequestAttributeAtOneBank)) - ) - - lazy val getTransactionRequestAttributeById: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transaction-requests" :: TransactionRequestId( - transactionRequestId - ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getTransactionRequestImpl( - transactionRequestId, - cc.callContext - ) - (transactionRequestAttribute, callContext) <- NewStyle.function - .getTransactionRequestAttributeById( - transactionRequestAttributeId, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionRequestAttributeJson( - transactionRequestAttribute - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionRequestAttributes, - implementedInApiVersion, - nameOf(getTransactionRequestAttributes), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes", - "Get Transaction Request Attributes", - s""" Get Transaction Request Attributes - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionRequestAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canGetTransactionRequestAttributesAtOneBank)) - ) - - lazy val getTransactionRequestAttributes: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transaction-requests" :: TransactionRequestId( - transactionRequestId - ) :: "attributes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getTransactionRequestImpl( - transactionRequestId, - cc.callContext - ) - (transactionRequestAttribute, callContext) <- NewStyle.function - .getTransactionRequestAttributes( - bankId, - transactionRequestId, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionRequestAttributesJson( - transactionRequestAttribute - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateTransactionRequestAttribute, - implementedInApiVersion, - nameOf(updateTransactionRequestAttribute), - "PUT", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID", - "Update Transaction Request Attribute", - s""" Update Transaction Request Attribute - | - |${userAuthenticationMessage(true)} - | - |""", - transactionRequestAttributeJsonV400, - transactionRequestAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canUpdateTransactionRequestAttributeAtOneBank)) - ) - - lazy val updateTransactionRequestAttribute: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transaction-requests" :: TransactionRequestId( - transactionRequestId - ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $TransactionRequestAttributeJsonV400" - for { - (_, callContext) <- NewStyle.function.getTransactionRequestImpl( - transactionRequestId, - cc.callContext - ) - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[TransactionRequestAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" - transactionRequestAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - TransactionRequestAttributeType.withName( - postedData.attribute_type - ) - } - (_, callContext) <- NewStyle.function - .getTransactionRequestAttributeById( - transactionRequestAttributeId, - callContext - ) - (transactionRequestAttribute, callContext) <- NewStyle.function - .createOrUpdateTransactionRequestAttribute( - bankId, - transactionRequestId, - Some(transactionRequestAttributeId), - postedData.name, - transactionRequestAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionRequestAttributeJson( - transactionRequestAttribute - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateTransactionRequestAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateTransactionRequestAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/transaction-request", - "Create or Update Transaction Request Attribute Definition", - s""" Create or Update Transaction Request Attribute Definition - | - |The category field must be ${AttributeCategory.TransactionRequest} - | - |The type field must be one of: ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - transactionRequestAttributeDefinitionJsonV400, - transactionRequestAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canCreateTransactionRequestAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateTransactionRequestAttributeDefinition - : OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER}(123) and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.TransactionRequest}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionRequestAttributeDefinition, - implementedInApiVersion, - nameOf(getTransactionRequestAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/transaction-request", - "Get Transaction Request Attribute Definition", - s""" Get Transaction Request Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionRequestAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canGetTransactionRequestAttributeDefinitionAtOneBank)) - ) - - lazy val getTransactionRequestAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName( - AttributeCategory.TransactionRequest.toString - ), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson( - attributeDefinitions - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteTransactionRequestAttributeDefinition, - implementedInApiVersion, - nameOf(deleteTransactionRequestAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction-request", - "Delete Transaction Request Attribute Definition", - s""" Delete Transaction Request Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), - Some(List(canDeleteTransactionRequestAttributeDefinitionAtOneBank)) - ) - - lazy val deleteTransactionRequestAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction-request" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName( - AttributeCategory.TransactionRequest.toString - ), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getSystemDynamicEntities, - implementedInApiVersion, - nameOf(getSystemDynamicEntities), - "GET", - "/management/system-dynamic-entities", - "Get System Dynamic Entities", - s"""Get all System Dynamic Entities. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )} """, - EmptyBody, - ListResult( - "dynamic_entities", - List(dynamicEntityResponseBodyExample) - ), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canGetSystemLevelDynamicEntities)) - ) - - lazy val getSystemDynamicEntities: OBPEndpoint = { - case "management" :: "system-dynamic-entities" :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicEntities <- Future( - NewStyle.function.getDynamicEntities(None, false) - ) - } yield { - val listCommons: List[DynamicEntityCommons] = dynamicEntities - val jObjects = listCommons.map(_.jValue) - ( - ListResult("dynamic_entities", jObjects), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelDynamicEntities, - implementedInApiVersion, - nameOf(getBankLevelDynamicEntities), - "GET", - "/management/banks/BANK_ID/dynamic-entities", - "Get Bank Level Dynamic Entities", - s"""Get all the bank level Dynamic Entities for one bank. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )}""", - EmptyBody, - ListResult( - "dynamic_entities", - List(dynamicEntityResponseBodyExample) - ), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities)) - ) - - lazy val getBankLevelDynamicEntities: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-entities" :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicEntities <- Future( - NewStyle.function.getDynamicEntities(Some(bankId), false) - ) - } yield { - val listCommons: List[DynamicEntityCommons] = dynamicEntities - val jObjects = listCommons.map(_.jValue) - ( - ListResult("dynamic_entities", jObjects), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - private def createDynamicEntityMethod( - cc: CallContext, - dynamicEntity: DynamicEntityCommons - ) = { - for { - Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( - dynamicEntity, - cc.callContext - ) - // granted the CRUD roles to the loggedIn User - curdRoles = List( - DynamicEntityInfo - .canCreateRole(result.entityName, dynamicEntity.bankId), - DynamicEntityInfo - .canUpdateRole(result.entityName, dynamicEntity.bankId), - DynamicEntityInfo.canGetRole(result.entityName, dynamicEntity.bankId), - DynamicEntityInfo.canDeleteRole( - result.entityName, - dynamicEntity.bankId - ) - ) - } yield { - curdRoles.map(role => - Entitlement.entitlement.vend.addEntitlement( - dynamicEntity.bankId.getOrElse(""), - cc.userId, - role.toString() - ) - ) - val commonsData: DynamicEntityCommons = result - (commonsData.jValue, HttpCode.`201`(cc.callContext)) - } - } - - private def createDynamicEntityDoc = ResourceDoc( - createSystemDynamicEntity, - implementedInApiVersion, - nameOf(createSystemDynamicEntity), - "POST", - "/management/system-dynamic-entities", - "Create System Level Dynamic Entity", - s"""Create a system level Dynamic Entity. - | - |Note: To see DynamicEntity in API Explorer II, find OBPdynamic-entity or similar in the list of API versions. - | - |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints. - | - |**Discovering the generated endpoints:** - | - |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use: - | - |`GET /resource-docs/API_VERSION/obp?content=dynamic` - | - |This returns documentation for all dynamic endpoints including paths, schemas, and required roles. - | - |For more information about Dynamic Entities see ${Glossary - .getGlossaryItemLink("Dynamic-Entities")} - | - | - |${userAuthenticationMessage(true)} - | - |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically - | - |The following field types are as supported: - |${DynamicEntityFieldType.values - .map(_.toString) - .mkString("[", ", ", ", reference]")} - | - |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} - | - |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. - | - |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity. - | - |To see the complete list of available reference types and their correct formats, call: - |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** - | - |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format. - | - |**The hasPersonalEntity flag:** - | - |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints. - |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records. - | - |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences. - | - |$dynamicEntityNamingExplanation - | - |**Example Request Body 1:** - |```json - |{ - | "AgentConversation": { - | "description": "Stores conversation metadata between users and agents", - | "required": ["conversation_id", "user_id"], - | "properties": { - | "conversation_id": { - | "type": "string", - | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1" - | }, - | "user_id": { - | "type": "string", - | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a" - | }, - | "title": { - | "type": "string", - | "example": "Stripe price ID error" - | }, - | "created_at": { - | "type": "string", - | "example": "2025-01-07T14:30:00.000Z" - | }, - | "model": { - | "type": "string", - | "example": "gpt-5" - | }, - | "language": { - | "type": "string", - | "example": "en" - | }, - | "metadata_platform": { - | "type": "string", - | "example": "web" - | }, - | "metadata_browser": { - | "type": "string", - | "example": "Firefox 144.0" - | }, - | "metadata_os": { - | "type": "string", - | "example": "Ubuntu 22.04" - | }, - | "tags": { - | "type": "string", - | "example": "stripe,api,error" - | }, - | "summary": { - | "type": "string", - | "example": "User received 'No such price' error using Stripe API" - | }, - | "custom_metadata": { - | "type": "json", - | "example": { - | "priority": "high", - | "tags": ["support", "billing"], - | "context": { - | "page": "checkout", - | "step": 3 - | } - | } - | } - | } - | }, - | "hasPersonalEntity": true - |} - |``` - | - | - |**Example 2: AgentMessage Entity with Reference to the above Entity** - |```json - |{ - | "hasPersonalEntity": true, - | "AgentMessage": { - | "description": "Stores individual messages within agent conversations", - | "required": [ - | "message_id", - | "conversation_id", - | "role" - | ], - | "properties": { - | "message_id": { - | "type": "string", - | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002" - | }, - | "conversation_id": { - | "type": "reference:AgentConversation", - | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388" - | }, - | "role": { - | "type": "string", - | "example": "user" - | }, - | "content_text": { - | "type": "string", - | "example": "I'm using Stripe for the first time and getting an error..." - | }, - | "timestamp": { - | "type": "string", - | "example": "2025-01-07T14:30:15.000Z" - | }, - | "token_count": { - | "type": "integer", - | "example": 150 - | }, - | "model_used": { - | "type": "string", - | "example": "gpt-5" - | } - | } - | } - |} - |``` - | - |$dynamicEntityImportantNotes - | - |$dynamicEntityGeneratedTags - | - |$dynamicEntityPianoExample - | - |**WRONG (will fail validation):** - |```json - |{ - | "entity": { - | "AgentConversation": { ... } - | } - |} - |``` - | - |**CORRECT:** - |```json - |{ - | "AgentConversation": { ... }, - | "hasPersonalEntity": true - |} - |``` - |""", - dynamicEntityRequestBodyExample.copy(bankId = None), - dynamicEntityResponseBodyExample.copy(bankId = None), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canCreateSystemLevelDynamicEntity)) - ) - - lazy val createSystemDynamicEntity: OBPEndpoint = { - case "management" :: "system-dynamic-entities" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val dynamicEntity = DynamicEntityCommons( - json.asInstanceOf[JObject], - None, - cc.userId, - None - ) - createDynamicEntityMethod(cc, dynamicEntity) - } - } - - private def createBankLevelDynamicEntityDoc = ResourceDoc( - createBankLevelDynamicEntity, - implementedInApiVersion, - nameOf(createBankLevelDynamicEntity), - "POST", - "/management/banks/BANK_ID/dynamic-entities", - "Create Bank Level Dynamic Entity", - s"""Create a Bank Level DynamicEntity. - | - |Note: Once you have created a DynamicEntity to see it in the API Explorer II, find OBPdynamic-entity or similar in the list of API versions. - | - |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints. - | - |**Discovering the generated endpoints:** - | - |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use: - | - |`GET /resource-docs/API_VERSION/obp?content=dynamic` - | - |This returns documentation for all dynamic endpoints including paths, schemas, and required roles. - | - |For more information about Dynamic Entities see ${Glossary - .getGlossaryItemLink("Dynamic-Entities")} - | - |${userAuthenticationMessage(true)} - | - |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically - | - |The following field types are as supported: - |${DynamicEntityFieldType.values - .map(_.toString) - .mkString("[", ", ", ", reference]")} - | - |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} - | - |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. - | - |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity. - | - |To see the complete list of available reference types and their correct formats, call: - |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** - | - |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format. - | - |**The hasPersonalEntity flag:** - | - |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints. - |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records. - | - |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences. - | - |$dynamicEntityNamingExplanation - | - |**Example Request Body 1:** - |```json - |{ - | "AgentConversation": { - | "description": "Stores conversation metadata between users and agents", - | "required": ["conversation_id", "user_id"], - | "properties": { - | "conversation_id": { - | "type": "string", - | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1" - | }, - | "user_id": { - | "type": "string", - | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a" - | }, - | "title": { - | "type": "string", - | "example": "Stripe price ID error" - | }, - | "created_at": { - | "type": "string", - | "example": "2025-01-07T14:30:00.000Z" - | }, - | "model": { - | "type": "string", - | "example": "gpt-5" - | }, - | "language": { - | "type": "string", - | "example": "en" - | }, - | "metadata_platform": { - | "type": "string", - | "example": "web" - | }, - | "metadata_browser": { - | "type": "string", - | "example": "Firefox 144.0" - | }, - | "metadata_os": { - | "type": "string", - | "example": "Ubuntu 22.04" - | }, - | "tags": { - | "type": "string", - | "example": "stripe,api,error" - | }, - | "summary": { - | "type": "string", - | "example": "User received 'No such price' error using Stripe API" - | }, - | "custom_metadata": { - | "type": "json", - | "example": { - | "priority": "high", - | "tags": ["support", "billing"], - | "context": { - | "page": "checkout", - | "step": 3 - | } - | } - | } - | } - | }, - | "hasPersonalEntity": true - |} - |``` - | - | - |**Example 2: AgentMessage Entity with Reference to the above Entity** - |```json - |{ - | "hasPersonalEntity": true, - | "AgentMessage": { - | "description": "Stores individual messages within agent conversations", - | "required": [ - | "message_id", - | "conversation_id", - | "role" - | ], - | "properties": { - | "message_id": { - | "type": "string", - | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002" - | }, - | "conversation_id": { - | "type": "reference:AgentConversation", - | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388" - | }, - | "role": { - | "type": "string", - | "example": "user" - | }, - | "content_text": { - | "type": "string", - | "example": "I'm using Stripe for the first time and getting an error..." - | }, - | "timestamp": { - | "type": "string", - | "example": "2025-01-07T14:30:15.000Z" - | }, - | "token_count": { - | "type": "integer", - | "example": 150 - | }, - | "model_used": { - | "type": "string", - | "example": "gpt-5" - | } - | } - | } - |} - |``` - | - |$dynamicEntityImportantNotes - | - |$dynamicEntityGeneratedTags - | - |$dynamicEntityPianoExample - | - |**WRONG (will fail validation):** - |```json - |{ - | "entity": { - | "AgentConversation": { ... } - | } - |} - |``` - | - |**CORRECT:** - |```json - |{ - | "AgentConversation": { ... }, - | "hasPersonalEntity": true - |} - |``` - |""", - dynamicEntityRequestBodyExample.copy(bankId = None), - dynamicEntityResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canCreateBankLevelDynamicEntity, canCreateAnyBankLevelDynamicEntity)) - ) - lazy val createBankLevelDynamicEntity: OBPEndpoint = { - case "management" :: "banks" :: BankId( - bankId - ) :: "dynamic-entities" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val dynamicEntity = DynamicEntityCommons( - json.asInstanceOf[JObject], - None, - cc.userId, - Some(bankId.value) - ) - createDynamicEntityMethod(cc, dynamicEntity) - } - } - - // bankId is option, if it is bankLevelEntity, we need BankId, if system Level Entity, bankId is None. - private def updateDynamicEntityMethod( - bankId: Option[String], - dynamicEntityId: String, - json: JValue, - cc: CallContext - ) = { - for { - // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity. - (entity, _) <- NewStyle.function.getDynamicEntityById( - bankId, - dynamicEntityId, - cc.callContext - ) - (box, _) <- NewStyle.function.invokeDynamicConnector( - GET_ALL, - entity.entityName, - None, - None, - entity.bankId, - None, - None, - false, - cc.callContext - ) - resultList: JArray = unboxResult( - box.asInstanceOf[Box[JArray]], - entity.entityName - ) - _ <- Helper.booleanToFuture( - DynamicEntityOperationNotAllowed, - cc = cc.callContext - ) { - resultList.arr.isEmpty - } - - jsonObject = json.asInstanceOf[JObject] - dynamicEntity = DynamicEntityCommons( - jsonObject, - Some(dynamicEntityId), - cc.userId, - bankId - ) - Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( - dynamicEntity, - cc.callContext - ) - } yield { - val commonsData: DynamicEntityCommons = result - (commonsData.jValue, HttpCode.`200`(cc.callContext)) - } - } - - private def updateDynamicEntityDoc = ResourceDoc( - updateSystemDynamicEntity, - implementedInApiVersion, - nameOf(updateSystemDynamicEntity), - "PUT", - "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID", - "Update System Level Dynamic Entity", - s"""Update a System Level Dynamic Entity. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )} - | - | - |${userAuthenticationMessage(true)} - | - |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. - | - |The following field types are as supported: - |${DynamicEntityFieldType.values - .map(_.toString) - .mkString("[", ", ", ", reference]")} - | - |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} - | - |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. - | - |To see all available reference types and their correct formats, call: - |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** - |""", - dynamicEntityRequestBodyExample.copy(bankId = None), - dynamicEntityResponseBodyExample.copy(bankId = None), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEntityNotFoundByDynamicEntityId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canUpdateSystemDynamicEntity)) - ) - lazy val updateSystemDynamicEntity: OBPEndpoint = { - case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateDynamicEntityMethod(None, dynamicEntityId, json, cc) - } - } - - private def updateBankLevelDynamicEntityDoc = ResourceDoc( - updateBankLevelDynamicEntity, - implementedInApiVersion, - nameOf(updateBankLevelDynamicEntity), - "PUT", - "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID", - "Update Bank Level Dynamic Entity", - s"""Update a Bank Level DynamicEntity. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )} - | - | - |${userAuthenticationMessage(true)} - | - |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. - | - |The following field types are as supported: - |${DynamicEntityFieldType.values - .map(_.toString) - .mkString("[", ", ", ", reference]")} - | - |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} - | - |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. - | - |To see all available reference types and their correct formats, call: - |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** - |""", - dynamicEntityRequestBodyExample.copy(bankId = None), - dynamicEntityResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canUpdateBankLevelDynamicEntity)) - ) - lazy val updateBankLevelDynamicEntity: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateDynamicEntityMethod(Some(bankId), dynamicEntityId, json, cc) - } - } - - staticResourceDocs += ResourceDoc( - deleteSystemDynamicEntity, - implementedInApiVersion, - nameOf(deleteSystemDynamicEntity), - "DELETE", - "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID", - "Delete System Level Dynamic Entity", - s"""Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )}/ - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canDeleteSystemLevelDynamicEntity)) - ) - lazy val deleteSystemDynamicEntity: OBPEndpoint = { - case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteDynamicEntityMethod(None, dynamicEntityId, cc) - } - } - - - - private def deleteDynamicEntityMethod( - bankId: Option[String], - dynamicEntityId: String, - cc: CallContext - ) = { - for { - // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity. - (entity, _) <- NewStyle.function.getDynamicEntityById( - bankId, - dynamicEntityId, - cc.callContext - ) - (box, _) <- NewStyle.function.invokeDynamicConnector( - GET_ALL, - entity.entityName, - None, - None, - entity.bankId, - None, - None, - false, - cc.callContext - ) - resultList: JArray = unboxResult( - box.asInstanceOf[Box[JArray]], - entity.entityName - ) - _ <- Helper.booleanToFuture( - DynamicEntityOperationNotAllowed, - cc = cc.callContext - ) { - resultList.arr.isEmpty - } - deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity( - bankId, - dynamicEntityId - ) - } yield { - (deleted, HttpCode.`200`(cc.callContext)) - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelDynamicEntity, - implementedInApiVersion, - nameOf(deleteBankLevelDynamicEntity), - "DELETE", - "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID", - "Delete Bank Level Dynamic Entity", - s"""Delete a Bank Level DynamicEntity specified by DYNAMIC_ENTITY_ID. - | - |For more information see ${Glossary.getGlossaryItemLink( - "Dynamic-Entities" - )}/ - | - |""", - EmptyBody, - EmptyBody, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi), - Some(List(canDeleteBankLevelDynamicEntity)) - ) - lazy val deleteBankLevelDynamicEntity: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteDynamicEntityMethod(Some(bankId), dynamicEntityId, cc) - } - } - - staticResourceDocs += ResourceDoc( - getMyDynamicEntities, - implementedInApiVersion, - nameOf(getMyDynamicEntities), - "GET", - "/my/dynamic-entities", - "Get My Dynamic Entities", - s"""Get all my Dynamic Entities (definitions I created). - | - |For more information see ${Glossary.getGlossaryItemLink( - "My-Dynamic-Entities" - )}""", - EmptyBody, - ListResult( - "dynamic_entities", - List(dynamicEntityResponseBodyExample) - ), - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi) - ) - - lazy val getMyDynamicEntities: OBPEndpoint = { - case "my" :: "dynamic-entities" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicEntities <- Future( - NewStyle.function.getDynamicEntitiesByUserId(cc.userId) - ) - } yield { - val listCommons: List[DynamicEntityCommons] = dynamicEntities - val jObjects = listCommons.map(_.jValue) - ( - ListResult("dynamic_entities", jObjects), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - private def updateMyDynamicEntityDoc = ResourceDoc( - updateMyDynamicEntity, - implementedInApiVersion, - nameOf(updateMyDynamicEntity), - "PUT", - "/my/dynamic-entities/DYNAMIC_ENTITY_ID", - "Update My Dynamic Entity", - s"""Update my DynamicEntity. - | - |For more information see ${Glossary.getGlossaryItemLink( - "My-Dynamic-Entities" - )}/ - | - | - |${userAuthenticationMessage(true)} - | - |Update one of my DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. - | - |Current support filed types as follow: - |${DynamicEntityFieldType.values - .map(_.toString) - .mkString("[", ", ", ", reference]")} - | - |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} - | - |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. - | - |To see all available reference types and their correct formats, call: - |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** - |""", - dynamicEntityRequestBodyExample.copy(bankId = None), - dynamicEntityResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - DynamicEntityNotFoundByDynamicEntityId, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi) - ) - - lazy val updateMyDynamicEntity: OBPEndpoint = { - case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicEntities <- Future( - NewStyle.function.getDynamicEntitiesByUserId(cc.userId) - ) - entityOption = dynamicEntities.find( - _.dynamicEntityId.equals(Some(dynamicEntityId)) - ) - myEntity <- NewStyle.function.tryons( - InvalidMyDynamicEntityUser, - 400, - cc.callContext - ) { - entityOption.get - } - // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity. - (box, _) <- NewStyle.function.invokeDynamicConnector( - GET_ALL, - myEntity.entityName, - None, - myEntity.dynamicEntityId, - myEntity.bankId, - None, - Some(myEntity.userId), - false, - cc.callContext - ) - resultList: JArray = unboxResult( - box.asInstanceOf[Box[JArray]], - myEntity.entityName - ) - _ <- Helper.booleanToFuture( - DynamicEntityOperationNotAllowed, - cc = cc.callContext - ) { - resultList.arr.isEmpty - } - jsonObject = json.asInstanceOf[JObject] - dynamicEntity = DynamicEntityCommons( - jsonObject, - Some(dynamicEntityId), - cc.userId, - myEntity.bankId - ) - Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( - dynamicEntity, - cc.callContext - ) - } yield { - val commonsData: DynamicEntityCommons = result - (commonsData.jValue, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyDynamicEntity, - implementedInApiVersion, - nameOf(deleteMyDynamicEntity), - "DELETE", - "/my/dynamic-entities/DYNAMIC_ENTITY_ID", - "Delete My Dynamic Entity", - s"""Delete my DynamicEntity specified by DYNAMIC_ENTITY_ID. - | - |For more information see ${Glossary.getGlossaryItemLink( - "My-Dynamic-Entities" - )} - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagManageDynamicEntity, apiTagApi) - ) - - lazy val deleteMyDynamicEntity: OBPEndpoint = { - case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicEntities <- Future( - NewStyle.function.getDynamicEntitiesByUserId(cc.userId) - ) - entityOption = dynamicEntities.find( - _.dynamicEntityId.equals(Some(dynamicEntityId)) - ) - myEntity <- NewStyle.function.tryons( - InvalidMyDynamicEntityUser, - 400, - cc.callContext - ) { - entityOption.get - } - // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity. - (box, _) <- NewStyle.function.invokeDynamicConnector( - GET_ALL, - myEntity.entityName, - None, - myEntity.dynamicEntityId, - myEntity.bankId, - None, - Some(myEntity.userId), - false, - cc.callContext - ) - resultList: JArray = unboxResult( - box.asInstanceOf[Box[JArray]], - myEntity.entityName - ) - _ <- Helper.booleanToFuture( - DynamicEntityOperationNotAllowed, - cc = cc.callContext - ) { - resultList.arr.isEmpty - } - deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity( - myEntity.bankId, - dynamicEntityId - ) - } yield { - (deleted, HttpCode.`200`(cc.callContext)) - } - } - } - - private def unboxResult[T: Manifest](box: Box[T], entityName: String): T = { - if (box.isInstanceOf[Failure]) { - val failure = box.asInstanceOf[Failure] - // change the internal db column name 'dynamicdataid' to entity's id name - val msg = failure.msg.replace( - DynamicData.DynamicDataId.dbColumnName, - StringUtils.uncapitalize(entityName) + "Id" - ) - val changedMsgFailure = failure.copy(msg = s"$InternalServerError $msg") - fullBoxOrException[T](changedMsgFailure) - } - - box.openOrThrowException("impossible error") - } - - staticResourceDocs += ResourceDoc( - resetPasswordUrl, - implementedInApiVersion, - nameOf(resetPasswordUrl), - "POST", - "/management/user/reset-password-url", - "Create password reset url", - s"""Create password reset url. - | - |""", - PostResetPasswordUrlJsonV400( - "jobloggs", - "jo@gmail.com", - "74a8ebcc-10e4-4036-bef3-9835922246bf" - ), - ResetPasswordUrlJsonV400( - "https://apisandbox.openbankproject.com/user_mgt/reset_password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L" - ), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagUser), - Some(List(canCreateResetPasswordUrl)) - ) - - lazy val resetPasswordUrl: OBPEndpoint = { - case "management" :: "user" :: "reset-password-url" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Helper.booleanToFuture( - failMsg = ErrorMessages.NotAllowedEndpoint, - cc = cc.callContext - ) { - APIUtil.getPropsAsBoolValue("ResetPasswordUrlEnabled", false) - } - failMsg = - s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordUrlJsonV400]} " - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[PostResetPasswordUrlJsonV400] - } - } yield { - val resetLink = AuthUser.passwordResetUrl( - postedData.username, - postedData.email, - postedData.user_id - ) - ( - ResetPasswordUrlJsonV400(resetLink), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - addAccount, - implementedInApiVersion, - nameOf(addAccount), - "POST", - "/banks/BANK_ID/accounts", - "Create Account (POST)", - """Create Account at bank specified by BANK_ID. - | - |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body. - | - |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID. - | - |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User. - | - |The 'product_code' field SHOULD be a product_code from Product. - |If the product_code matches a product_code from Product, account attributes will be created that match the Product Attributes. - | - |Note: The Amount MUST be zero.""".stripMargin, - createAccountRequestJsonV310, - createAccountResponseJsonV310, - List( - InvalidJsonFormat, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidAccountBalanceAmount, - InvalidAccountInitialBalance, - InitialBalanceMustBeZero, - InvalidAccountBalanceCurrency, - UnknownError - ), - List(apiTagAccount), - Some(List(canCreateAccount)) - ).disableAutoValidateRoles() // this means disabled auto roles validation, will manually do the roles validation . - - lazy val addAccount: OBPEndpoint = { - // Create a new account - case "banks" :: BankId( - bankId - ) :: "accounts" :: Nil JsonPost json -> _ => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} " - for { - createAccountJson <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[CreateAccountRequestJsonV310] - } - loggedInUserId = cc.userId - userIdAccountOwner = - if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id - else loggedInUserId - (postedOrLoggedInUser, callContext) <- NewStyle.function - .findByUserId(userIdAccountOwner, cc.callContext) - - _ <- - if (userIdAccountOwner == loggedInUserId) - Future.successful(Full(Unit)) - else - NewStyle.function.hasEntitlement( - bankId.value, - loggedInUserId, - canCreateAccount, - callContext, - s"${UserHasMissingRoles} $canCreateAccount or create account for self" - ) - - initialBalanceAsString = createAccountJson.balance.amount - // Note: here we map the product_code to account_type - accountType = createAccountJson.product_code - accountLabel = createAccountJson.label - initialBalanceAsNumber <- NewStyle.function.tryons( - InvalidAccountInitialBalance, - 400, - callContext - ) { - BigDecimal(initialBalanceAsString) - } - _ <- Helper.booleanToFuture( - InitialBalanceMustBeZero, - cc = callContext - ) { 0 == initialBalanceAsNumber } - _ <- Helper.booleanToFuture( - InvalidISOCurrencyCode, - cc = callContext - ) { - APIUtil.isValidCurrencyISOCode(createAccountJson.balance.currency) - } - currency = createAccountJson.balance.currency - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - _ <- Helper.booleanToFuture( - s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", - cc = callContext - ) { - createAccountJson.account_routings - .map(_.scheme) - .distinct - .size == createAccountJson.account_routings.size - } - alreadyExistAccountRoutings <- Future.sequence( - createAccountJson.account_routings.map(accountRouting => - NewStyle.function - .getAccountRouting( - Some(bankId), - accountRouting.scheme, - accountRouting.address, - callContext - ) - .map(_ => Some(accountRouting)) - .fallbackTo(Future.successful(None)) - ) - ) - alreadyExistingAccountRouting = alreadyExistAccountRoutings - .collect { case Some(accountRouting) => - s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" - } - _ <- Helper.booleanToFuture( - s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", - cc = callContext - ) { - alreadyExistingAccountRouting.isEmpty - } - (bankAccount, callContext) <- NewStyle.function.createBankAccount( - bankId, - AccountId(APIUtil.generateUUID()), - accountType, - accountLabel, - currency, - initialBalanceAsNumber, - postedOrLoggedInUser.name, - createAccountJson.branch_id, - createAccountJson.account_routings.map(r => - AccountRouting(r.scheme, r.address) - ), - callContext - ) - accountId = bankAccount.accountId - (productAttributes, callContext) <- NewStyle.function - .getProductAttributesByBankAndCode( - bankId, - ProductCode(accountType), - callContext - ) - (accountAttributes, callContext) <- NewStyle.function - .createAccountAttributes( - bankId, - accountId, - ProductCode(accountType), - productAttributes, - None, - callContext: Option[CallContext] - ) - // 1 Create or Update the `Owner` for the new account - // 2 Add permission to the user - // 3 Set the user as the account holder - _ <- BankAccountCreation - .setAccountHolderAndRefreshUserAccountAccess( - bankId, - accountId, - postedOrLoggedInUser, - callContext - ) - } yield { - ( - JSONFactory310.createAccountJSON( - userIdAccountOwner, - bankAccount, - accountAttributes - ), - HttpCode.`201`(callContext) - ) - } - } - } - } - - staticResourceDocs += ResourceDoc( - root, - implementedInApiVersion, - "root", - "GET", - "/root", - "Get API Info (root)", - """Returns information about: - | - |* API version - |* Hosted by information - |* Hosted at information - |* Energy source information - |* Git Commit""", - EmptyBody, - apiInfoJson400, - List(UnknownError, MandatoryPropertyIsNotSet), - apiTagApi :: Nil - ) - - lazy val root: OBPEndpoint = { - case (Nil | "root" :: Nil) JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Future(()) // Just start async call - } yield { - ( - JSONFactory400.getApiInfoJSON( - OBPAPI4_0_0.version, - OBPAPI4_0_0.versionStatus - ), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCallContext, - implementedInApiVersion, - nameOf(getCallContext), - "GET", - "/development/call_context", - "Get the Call Context of a current call", - s"""Get the Call Context of the current call. - | - """.stripMargin, - EmptyBody, - EmptyBody, - List($AuthenticatedUserIsRequired, UnknownError), - List(apiTagApi), - Some(List(canGetCallContext)) - ) - - lazy val getCallContext: OBPEndpoint = { - case "development" :: "call_context" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Future(()) // Just start async call - } yield { - (cc.callContext, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - verifyRequestSignResponse, - implementedInApiVersion, - nameOf(verifyRequestSignResponse), - "GET", - "/development/echo/jws-verified-request-jws-signed-response", - "Verify Request and Sign Response of a current call", - s"""Verify Request and Sign Response of a current call. - | - """.stripMargin, - EmptyBody, - EmptyBody, - List($AuthenticatedUserIsRequired, UnknownError), - List(apiTagApi), - Some(Nil) - ) - - lazy val verifyRequestSignResponse: OBPEndpoint = { - case "development" :: "echo" :: "jws-verified-request-jws-signed-response" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Future(()) // Just start async call - } yield { - (cc.callContext, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAccountLabel, - implementedInApiVersion, - "updateAccountLabel", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID", - "Update Account Label", - s"""Update the label for the account. The label is how the account is known to the account owner e.g. 'My savings account' - | - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - updateAccountJsonV400, - successMessage, - List( - InvalidJsonFormat, - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError, - $BankAccountNotFound, - "user does not have access to owner view on account" - ), - List(apiTagAccount) - ) - - lazy val updateAccountLabel: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), account, callContext) <- SS.userAccount - failMsg = - s"$InvalidJsonFormat The Json body should be the $InvalidJsonFormat " - json <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[UpdateAccountJsonV400] - } - anyViewContainsCanUpdateBankAccountLabelPermission = Views.views.vend - .permission(BankIdAccountId(account.bankId, account.accountId), u) - .map( - _.views.map( - _.allowed_actions.exists(_ == CAN_UPDATE_BANK_ACCOUNT_LABEL) - ) - ) - .getOrElse(Nil) - .find(_.==(true)) - .getOrElse(false) - _ <- Helper.booleanToFuture( - s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_UPDATE_BANK_ACCOUNT_LABEL)}` permission on any your views", - cc = callContext - ) { - anyViewContainsCanUpdateBankAccountLabelPermission - } - (success, callContext) <- Connector.connector.vend.updateAccountLabel( - bankId, - accountId, - json.label, - callContext - ) map { i => - ( - unboxFullOrFail( - i._1, - i._2, - s"$UpdateBankAccountLabelError Current BankId is $bankId and Current AccountId is $accountId", - 404 - ), - i._2 - ) - } - } yield { - (Extraction.decompose(successMessage), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - lockUser, - implementedInApiVersion, - nameOf(lockUser), - "POST", - "/users/USERNAME/locks", - "Lock the user", - s""" - |Lock a User. - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - userLockStatusJson, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByProviderAndUsername, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canLockUser)) - ) - - lazy val lockUser: OBPEndpoint = { - case "users" :: username :: "locks" :: Nil JsonPost req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - userLocks <- Future { - UserLocksProvider.lockUser(localIdentityProvider, username) - } map { - unboxFullOrFail( - _, - callContext, - s"$UserNotFoundByProviderAndUsername($username)", - 404 - ) - } - } yield { - ( - JSONFactory400.createUserLockStatusJson(userLocks), - HttpCode.`200`(callContext) - ) - } - } - } - staticResourceDocs += ResourceDoc( - createUserWithRoles, - implementedInApiVersion, - nameOf(createUserWithRoles), - "POST", - "/user-entitlements", - "Create (DAuth) User with Roles", - s""" - |This endpoint is used as part of the DAuth solution to grant Entitlements for Roles to a smart contract on the blockchain. - | - |Put the smart contract address in username - | - |For provider use "dauth" - | - |This endpoint will create the User with username and provider if the User does not already exist. - | - |Then it will create Entitlements i.e. grant Roles to the User. - | - |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views) - | - |i.e. Entitlements are used to create / consume system or bank level resources where as views / account access are used to consume / create customer level resources. - | - |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":"" - | - |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id" - | - |Note: The Roles actually granted will depend on the Roles that the calling user has. - | - |If you try to grant Entitlements to a user that already exist (duplicate entitilements) you will get an error. - | - |For information about DAuth see below: - | - |${getGlossaryItem("DAuth")} - | - |""", - postCreateUserWithRolesJsonV400, - entitlementsJsonV400, - List( - AuthenticatedUserIsRequired, - InvalidJsonFormat, - IncorrectRoleName, - EntitlementIsBankRole, - EntitlementIsSystemRole, - EntitlementAlreadyExists, - InvalidUserProvider, - UnknownError - ), - List(apiTagRole, apiTagEntitlement, apiTagUser, apiTagDAuth) - ) - - lazy val createUserWithRoles: OBPEndpoint = { - case "user-entitlements" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(loggedInUser), callContext) <- authenticatedAccess(cc) - failMsg = - s"$InvalidJsonFormat The Json body should be the $PostCreateUserWithRolesJsonV400 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostCreateUserWithRolesJsonV400] - } - - // provider must start with dauth., can not create other provider users. - _ <- Helper.booleanToFuture( - s"$InvalidUserProvider The user.provider must be start with 'dauth.'", - cc = Some(cc) - ) { - postedData.provider.startsWith("dauth.") - } - - // check the system role bankId is Empty, but bank level role need bankId - _ <- checkRoleBankIdMappings(callContext, postedData) - - _ <- checkRolesBankIdExsiting(callContext, postedData) - - _ <- checkRolesName(callContext, postedData) - - canCreateEntitlementAtAnyBankRole = Entitlement.entitlement.vend - .getEntitlement( - "", - loggedInUser.userId, - canCreateEntitlementAtAnyBank.toString() - ) - - (targetUser, callContext) <- NewStyle.function - .getOrCreateResourceUser( - postedData.provider, - postedData.username, - callContext - ) - - _ <- - if (canCreateEntitlementAtAnyBankRole.isDefined) { - // If the loggedIn User has `CanCreateEntitlementAtAnyBankRole` role, then we can grant all the requestRoles to the requestUser. - // But we must check if the requestUser already has the requestRoles or not. - assertTargetUserLacksRoles( - targetUser.userId, - postedData.roles, - callContext - ) - } else { - // If the loggedIn user does not have the `CanCreateEntitlementAtAnyBankRole` role, we can only grant the roles which the loggedIn user have. - // So we need to check if the requestRoles are beyond the current loggedIn user has. - assertUserCanGrantRoles( - loggedInUser.userId, - postedData.roles, - callContext - ) - } - - addedEntitlements <- addEntitlementsToUser( - targetUser.userId, - postedData, - callContext - ) - - } yield { - ( - JSONFactory400.createEntitlementJSONs(addedEntitlements), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getEntitlements, - implementedInApiVersion, - "getEntitlements", - "GET", - "/users/USER_ID/entitlements", - "Get Entitlements for User", - s""" - | - | - """.stripMargin, - EmptyBody, - entitlementsJsonV400, - List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError), - List(apiTagRole, apiTagEntitlement, apiTagUser), - Some(List(canGetEntitlementsForAnyUserAtAnyBank)) - ) - - lazy val getEntitlements: OBPEndpoint = { - case "users" :: userId :: "entitlements" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - entitlements <- NewStyle.function.getEntitlementsByUserId( - userId, - cc.callContext - ) - } yield { - // Add virtual entitlements for super_admin_user_ids or oidc_operator_user_ids - val json = if (isSuperAdmin(userId)) { - JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.superAdminVirtualRoles) - } else if (isOidcOperator(userId)) { - JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.oidcOperatorVirtualRoles) - } else { - JSONFactory200.createEntitlementJSONs(entitlements) - } - (json, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getEntitlementsForBank, - implementedInApiVersion, - nameOf(getEntitlementsForBank), - "GET", - "/banks/BANK_ID/entitlements", - "Get Entitlements for One Bank", - s""" - | - """.stripMargin, - EmptyBody, - entitlementsJsonV400, - List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError), - List(apiTagRole, apiTagEntitlement, apiTagUser), - Some(List(canGetEntitlementsForOneBank, canGetEntitlementsForAnyBank)) - ) - - val allowedEntitlements = - canGetEntitlementsForOneBank :: canGetEntitlementsForAnyBank :: Nil - val allowedEntitlementsTxt = allowedEntitlements.mkString(" or ") - - lazy val getEntitlementsForBank: OBPEndpoint = { - case "banks" :: bankId :: "entitlements" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - entitlements <- NewStyle.function.getEntitlementsByBankId( - bankId, - cc.callContext - ) - } yield { - val json = JSONFactory400.createEntitlementJSONs(entitlements) - (json, HttpCode.`200`(cc.callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - addTagForViewOnAccount, - implementedInApiVersion, - "addTagForViewOnAccount", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags", - "Create a tag on account", - s"""Posts a tag about an account ACCOUNT_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID. - | - |${userAuthenticationMessage(true)} - | - |Authentication is required as the tag is linked with the user.""", - postAccountTagJSON, - accountTagJSON, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - InvalidJsonFormat, - NoViewPermission, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagAccountMetadata, apiTagAccount) - ) - - lazy val addTagForViewOnAccount: OBPEndpoint = { - // add a tag - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId( - viewId - ) :: "metadata" :: "tags" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = s"$NoViewPermission can_add_tag. Current ViewId($viewId)", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_ADD_TAG) - } - tagJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostTransactionTagJSON ", - 400, - callContext - ) { - json.extract[PostTransactionTagJSON] - } - (postedTag, callContext) <- Future( - Tags.tags.vend.addTagOnAccount(bankId, accountId)( - u.userPrimaryKey, - viewId, - tagJson.value, - now - ) - ) map { i => - (connectorEmptyResponse(i, callContext), callContext) - } - } yield { - ( - JSONFactory400.createAccountTagJSON(postedTag), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteTagForViewOnAccount, - implementedInApiVersion, - "deleteTagForViewOnAccount", - "DELETE", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags/TAG_ID", - "Delete a tag on account", - s"""Deletes the tag TAG_ID about the account ACCOUNT_ID made on [view](#1_2_1-getViewsForBankAccount). - | - |${userAuthenticationMessage(true)} - | - |Authentication is required as the tag is linked with the user.""", - EmptyBody, - EmptyBody, - List( - NoViewPermission, - ViewNotFound, - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagAccountMetadata, apiTagAccount) - ) - - lazy val deleteTagForViewOnAccount: OBPEndpoint = { - // delete a tag - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId( - viewId - ) :: "metadata" :: "tags" :: tagId :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = - s"$NoViewPermission can_delete_tag. Current ViewId($viewId)", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_DELETE_TAG) - } - deleted <- Future( - Tags.tags.vend.deleteTagOnAccount(bankId, accountId)(tagId) - ) map { i => - (connectorEmptyResponse(i, callContext), callContext) - } - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getTagsForViewOnAccount, - implementedInApiVersion, - "getTagsForViewOnAccount", - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags", - "Get tags on account", - s"""Returns the account ACCOUNT_ID tags made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID). - |${userAuthenticationMessage(true)} - | - |Authentication is required as the tag is linked with the user.""", - EmptyBody, - accountTagsJSON, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - NoViewPermission, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagAccountMetadata, apiTagAccount) - ) - - lazy val getTagsForViewOnAccount: OBPEndpoint = { - // get tags - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "metadata" :: "tags" :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = - s"$NoViewPermission can_see_tags. Current ViewId($viewId)", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_SEE_TAGS) - } - tags <- Future( - Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId) - ) - } yield { - val json = JSONFactory400.createAccountTagsJSON(tags) - (json, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getCoreAccountById, - implementedInApiVersion, - nameOf(getCoreAccountById), - "GET", - "/my/banks/BANK_ID/accounts/ACCOUNT_ID/account", - "Get Account by Id (Core)", - s"""Information returned about the account specified by ACCOUNT_ID: - | - |* Number - The human readable account number given by the bank that identifies the account. - |* Label - A label given by the owner of the account - |* Owners - Users that own this account - |* Type - The type of account - |* Balance - Currency and Value - |* Account Routings - A list that might include IBAN or national account identifiers - |* Account Rules - A list that might include Overdraft and other bank specific rules - |* Tags - A list of Tags assigned to this account - | - |This call returns the owner view and requires access to that view. - | - | - |""".stripMargin, - EmptyBody, - moderatedCoreAccountJsonV400, - List($AuthenticatedUserIsRequired, $BankAccountNotFound, UnknownError), - apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - lazy val getCoreAccountById: OBPEndpoint = { - // get account by id (assume owner view requested) - case "my" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "account" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), account, callContext) <- SS.userAccount - view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( - u, - BankIdAccountId(account.bankId, account.accountId), - callContext - ) - moderatedAccount <- NewStyle.function.moderatedBankAccountCore( - account, - view, - user, - callContext - ) - } yield { - val availableViews: List[View] = - Views.views.vend.privateViewsUserCanAccessForAccount( - u, - BankIdAccountId(account.bankId, account.accountId) - ) - ( - createNewCoreBankAccountJson(moderatedAccount, availableViews), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getPrivateAccountByIdFull, - implementedInApiVersion, - nameOf(getPrivateAccountByIdFull), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account", - "Get Account by Id (Full)", - """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID): - | - |* Number - |* Owners - |* Type - |* Balance - |* IBAN - |* Available views (sorted by short_name) - | - |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount). - | - |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications. - |This call provides balance and other account information via delegated authentication using OAuth. - | - |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`. - |""".stripMargin, - EmptyBody, - moderatedAccountJSON400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - apiTagAccount :: Nil - ) - lazy val getPrivateAccountByIdFull: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - moderatedAccount <- NewStyle.function.moderatedBankAccountCore( - account, - view, - user, - callContext - ) - (accountAttributes, callContext) <- NewStyle.function - .getAccountAttributesByAccount( - bankId, - accountId, - callContext: Option[CallContext] - ) - } yield { - val availableViews = - Views.views.vend.privateViewsUserCanAccessForAccount( - u, - BankIdAccountId(account.bankId, account.accountId) - ) - val viewsAvailable = - availableViews.map(JSONFactory.createViewJSON).sortBy(_.short_name) - val tags = Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId) - ( - createBankAccountJSON( - moderatedAccount, - viewsAvailable, - accountAttributes, - tags - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getAccountByAccountRouting, - implementedInApiVersion, - nameOf(getAccountByAccountRouting), - "POST", - "/management/accounts/account-routing-query", - "Get Account by Account Routing", - """This endpoint returns the account (if it exists) linked with the provided scheme and address. - | - |The `bank_id` field is optional, but if it's not provided, we don't guarantee that the returned account is unique across all the banks. - | - |Example of account routing scheme: `IBAN`, "OBP", "AccountNumber", ... - |Example of account routing address: `DE17500105178275645584`, "321774cc-fccd-11ea-adc1-0242ac120002", "55897106215", ... - | - |""".stripMargin, - bankAccountRoutingJson, - moderatedAccountJSON400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagAccount) - ) - lazy val getAccountByAccountRouting: OBPEndpoint = { - case "management" :: "accounts" :: "account-routing-query" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121" - for { - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[BankAccountRoutingJson] - } - - (account, callContext) <- NewStyle.function.getBankAccountByRouting( - postJson.bank_id.map(BankId(_)), - postJson.account_routing.scheme, - postJson.account_routing.address, - cc.callContext - ) - - user @ Full(u) = cc.user - view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( - u, - BankIdAccountId(account.bankId, account.accountId), - callContext - ) - moderatedAccount <- NewStyle.function.moderatedBankAccountCore( - account, - view, - user, - callContext - ) - - (accountAttributes, callContext) <- NewStyle.function - .getAccountAttributesByAccount( - account.bankId, - account.accountId, - callContext: Option[CallContext] - ) - } yield { - val availableViews = - Views.views.vend.privateViewsUserCanAccessForAccount( - cc.user.openOrThrowException("Exception user"), - BankIdAccountId(account.bankId, account.accountId) - ) - val viewsAvailable = availableViews - .map(JSONFactory.createViewJSON) - .sortBy(_.short_name) - val tags = Tags.tags.vend - .getTagsOnAccount(account.bankId, account.accountId)(view.viewId) - ( - createBankAccountJSON( - moderatedAccount, - viewsAvailable, - accountAttributes, - tags - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getAccountsByAccountRoutingRegex, - implementedInApiVersion, - nameOf(getAccountsByAccountRoutingRegex), - "POST", - "/management/accounts/account-routing-regex-query", - "Get Accounts by Account Routing Regex", - """This endpoint returns an array of accounts matching the provided routing scheme and the routing address regex. - | - |The `bank_id` field is optional. - | - |Example of account routing scheme: `IBAN`, `OBP`, `AccountNumber`, ... - |Example of account routing address regex: `DE175.*`, `55897106215-[A-Z]{3}`, ... - | - |This endpoint can be used to retrieve multiples accounts matching a same account routing address pattern. - |For example, if you want to link multiple accounts having different currencies, you can create an account - |with `123456789-EUR` as Account Number and an other account with `123456789-USD` as Account Number. - |So we can identify the Account Number as `123456789`, so to get all the accounts with the same account number - |and the different currencies, we can use this body in the request : - | - |``` - |{ - | "bank_id": "BANK_ID", - | "account_routing": { - | "scheme": "AccountNumber", - | "address": "123456789-[A-Z]{3}" - | } - |} - |``` - | - |This request will returns the accounts matching the routing address regex (`123456789-EUR` and `123456789-USD`). - | - |""".stripMargin, - bankAccountRoutingJson, - moderatedAccountsJSON400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagAccount) - ) - lazy val getAccountsByAccountRoutingRegex: OBPEndpoint = { - case "management" :: "accounts" :: "account-routing-regex-query" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121" - for { - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[BankAccountRoutingJson] - } - - (accountRoutings, callContext) <- NewStyle.function - .getAccountRoutingsByScheme( - postJson.bank_id.map(BankId(_)), - postJson.account_routing.scheme, - cc.callContext - ) - - accountRoutingAddressRegex = postJson.account_routing.address.r - filteredAccountRoutings = accountRoutings.filter(accountRouting => - accountRoutingAddressRegex - .findFirstIn(accountRouting.accountRouting.address) - .isDefined - ) - - user @ Full(u) = cc.user - - accountsJson <- Future.sequence( - filteredAccountRoutings.map(accountRouting => - for { - (account, callContext) <- NewStyle.function.getBankAccount( - accountRouting.bankId, - accountRouting.accountId, - callContext - ) - view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( - u, - BankIdAccountId(account.bankId, account.accountId), - callContext - ) - moderatedAccount <- NewStyle.function - .moderatedBankAccountCore(account, view, user, callContext) - (accountAttributes, callContext) <- NewStyle.function - .getAccountAttributesByAccount( - account.bankId, - account.accountId, - callContext: Option[CallContext] - ) - availableViews = Views.views.vend - .privateViewsUserCanAccessForAccount( - cc.user.openOrThrowException("Exception user"), - BankIdAccountId(account.bankId, account.accountId) - ) - viewsAvailable = availableViews - .map(JSONFactory.createViewJSON) - .sortBy(_.short_name) - tags = Tags.tags.vend.getTagsOnAccount( - account.bankId, - account.accountId - )(view.viewId) - } yield createBankAccountJSON( - moderatedAccount, - viewsAvailable, - accountAttributes, - tags - ) - ) - ) - } yield { - ( - ModeratedAccountsJSON400(accountsJson), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankAccountsBalancesForCurrentUser, - implementedInApiVersion, - nameOf(getBankAccountsBalancesForCurrentUser), - "GET", - "/banks/BANK_ID/balances", - "Get Accounts Balances", - """Get the Balances for the Accounts of the current User at one bank.""", - EmptyBody, - accountBalancesV400Json, - List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError), - apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - - lazy val getBankAccountsBalancesForCurrentUser: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - (allowedAccounts, callContext) <- BalanceNewStyle - .getAccountAccessAtBank(u, bankId, callContext) - (accountsBalances, callContext) <- BalanceNewStyle - .getBankAccountsBalances(allowedAccounts, callContext) - } yield { - (createBalancesJson(accountsBalances), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankAccountBalancesForCurrentUser, - implementedInApiVersion, - nameOf(getBankAccountBalancesForCurrentUser), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/balances", - "Get Account Balances", - """Get the Balances for one Account of the current User at one bank.""", - EmptyBody, - accountBalanceV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - CannotFindAccountAccess, - UnknownError - ), - apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil - ) - - lazy val getBankAccountBalancesForCurrentUser: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "balances" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - (allowedAccounts, callContext) <- BalanceNewStyle - .getAccountAccessAtBank(u, bankId, callContext) - msg = s"$CannotFindAccountAccess AccountId(${accountId.value})" - bankIdAccountId <- NewStyle.function.tryons( - msg, - 400, - cc.callContext - ) { - allowedAccounts.find(_.accountId == accountId).get - } - (accountBalances, callContext) <- BalanceNewStyle - .getBankAccountBalances(bankIdAccountId, callContext) - } yield { - ( - createAccountBalancesJson(accountBalances), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getFirehoseAccountsAtOneBank, - implementedInApiVersion, - nameOf(getFirehoseAccountsAtOneBank), - "GET", - "/banks/BANK_ID/firehose/accounts/views/VIEW_ID", - "Get Firehose Accounts at Bank", - s""" - |Get all Accounts at a Bank. - | - |This endpoint allows bulk access to all accounts at the specified bank. - | - |Requires the CanUseFirehoseAtAnyBank Role or CanUseAccountFirehose Role - | - |Returns all accounts at the bank. The VIEW_ID parameter determines what account data fields are visible according to the view's permissions. - | - |The view specified must have is_firehose = true - | - |For VIEW_ID try 'owner' or 'firehose' - | - |Optional request parameters for filtering by account attributes: - |URL params example: - | /banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1 - | - |To invalidate browser cache, add timestamp query parameter as follows (the parameter name must be `_timestamp_`): - |URL params example: - | `/banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1&_timestamp_=1596762180358` - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - moderatedFirehoseAccountsJsonV400, - List($BankNotFound), - List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData), - Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose)) - ) - - lazy val getFirehoseAccountsAtOneBank: OBPEndpoint = { - // get private accounts for all banks - case "banks" :: BankId( - bankId - ) :: "firehose" :: "accounts" :: "views" :: ViewId( - viewId - ) :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), bank, callContext) <- SS.userBank - _ <- Helper.booleanToFuture( - failMsg = AccountFirehoseNotAllowedOnThisInstance, - cc = cc.callContext - ) { - allowAccountFirehose - } - // here must be a system view, not accountIds in the URL - view <- ViewNewStyle.checkViewAccessAndReturnView( - viewId, - BankIdAccountId(bankId, AccountId("")), - Some(u), - callContext - ) - availableBankIdAccountIdList <- Future { - Views.views.vend - .getAllFirehoseAccounts(bank.bankId) - .map(a => BankIdAccountId(a.bankId, a.accountId)) - } - params = req.params - .filterNot( - _._1 == PARAM_TIMESTAMP - ) // ignore `_timestamp_` parameter, it is for invalid Browser caching - .filterNot(_._1 == PARAM_LOCALE) - availableBankIdAccountIdList2 <- - if (params.isEmpty) { - Future.successful(availableBankIdAccountIdList) - } else { - AccountAttributeX.accountAttributeProvider.vend - .getAccountIdsByParams(bankId, params) - .map { boxedAccountIds => - val accountIds = boxedAccountIds.getOrElse(Nil) - availableBankIdAccountIdList.filter( - availableBankIdAccountId => - accountIds - .contains(availableBankIdAccountId.accountId.value) - ) - } - } - moderatedAccounts: List[ModeratedBankAccount] = for { - // Here is a new for-loop to get the moderated accouts for the firehose user, according to the viewId. - // 1 each accountId-> find a proper bankAccount object. - // 2 each bankAccount object find the proper view. - // 3 use view and user to moderate the bankaccount object. - bankIdAccountId <- availableBankIdAccountIdList2 - (bankAccount, callContext) <- Connector.connector.vend - .getBankAccountLegacy( - bankIdAccountId.bankId, - bankIdAccountId.accountId, - callContext - ) ?~! s"$BankAccountNotFound Current Bank_Id(${bankIdAccountId.bankId}), Account_Id(${bankIdAccountId.accountId}) " - moderatedAccount <- bankAccount.moderatedBankAccount( - view, - bankIdAccountId, - Full(u), - callContext - ) // Error handling is in lower method - } yield { - moderatedAccount - } - // if there are accountAttribute query parameter, link to corresponding accountAttributes. - (accountAttributes: Option[List[AccountAttribute]], callContext) <- - if (moderatedAccounts.nonEmpty && params.nonEmpty) { - val futures: List[OBPReturnType[List[AccountAttribute]]] = - availableBankIdAccountIdList2.map { bankIdAccount => - val BankIdAccountId(bId, accountId) = bankIdAccount - NewStyle.function.getAccountAttributesByAccount( - bId, - accountId, - callContext: Option[CallContext] - ) - } - Future.reduceLeft(futures) { (r, t) => // combine to one future - r.copy(_1 = t._1 ::: t._1) - } map (it => - (Some(it._1), it._2) - ) // convert list to Option[List[AccountAttribute]] - } else { - Future.successful(None, callContext) - } - } yield { - ( - JSONFactory400.createFirehoseCoreBankAccountJSON( - moderatedAccounts, - accountAttributes - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getFastFirehoseAccountsAtOneBank, - implementedInApiVersion, - nameOf(getFastFirehoseAccountsAtOneBank), - "GET", - "/management/banks/BANK_ID/fast-firehose/accounts", - "Get Fast Firehose Accounts at Bank", - s""" - | - |This endpoint allows bulk access to accounts. - | - |optional pagination parameters for filter with accounts - |${urlParametersDocument(true, false)} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - fastFirehoseAccountsJsonV400, - List($BankNotFound), - List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData), - Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose)) - ) - - lazy val getFastFirehoseAccountsAtOneBank: OBPEndpoint = { - // get private accounts for all banks - case "management" :: "banks" :: BankId( - bankId - ) :: "fast-firehose" :: "accounts" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), bank, callContext) <- SS.userBank - _ <- Helper.booleanToFuture( - failMsg = AccountFirehoseNotAllowedOnThisInstance, - cc = cc.callContext - ) { - allowAccountFirehose - } - allowedParams = List("limit", "offset", "sort_direction") - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - (obpQueryParams, callContext) <- NewStyle.function.createObpParams( - httpParams, - allowedParams, - callContext - ) - (firehoseAccounts, callContext) <- NewStyle.function - .getBankAccountsWithAttributes(bankId, obpQueryParams, callContext) - } yield { - ( - JSONFactory400.createFirehoseBankAccountJSON(firehoseAccounts), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomersByCustomerPhoneNumber, - implementedInApiVersion, - nameOf(getCustomersByCustomerPhoneNumber), - "POST", - "/banks/BANK_ID/search/customers/mobile-phone-number", - "Get Customers by MOBILE_PHONE_NUMBER", - s"""Gets the Customers specified by MOBILE_PHONE_NUMBER. - | - |There are two wildcards often used in conjunction with the LIKE operator: - | % - The percent sign represents zero, one, or multiple characters - | _ - The underscore represents a single character - |For example {"customer_phone_number":"%381%"} lists all numbers which contain 381 sequence - | - |""", - postCustomerPhoneNumberJsonV400, - customerJsonV310, - List( - $AuthenticatedUserIsRequired, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer, apiTagKyc), - Some(List(canGetCustomersAtOneBank)) - ) - - lazy val getCustomersByCustomerPhoneNumber: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "search" :: "customers" :: "mobile-phone-number" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostCustomerPhoneNumberJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[PostCustomerPhoneNumberJsonV400] - } - (customers, callContext) <- NewStyle.function - .getCustomersByCustomerPhoneNumber( - bankId, - postedData.mobile_phone_number, - cc.callContext - ) - } yield { - ( - JSONFactory300.createCustomersJson(customers), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCurrentUserId, - implementedInApiVersion, - nameOf(getCurrentUserId), - "GET", - "/users/current/user_id", - "Get User Id (Current)", - s"""Get the USER_ID of the logged in user - | - |${userAuthenticationMessage(true)} - """.stripMargin, - EmptyBody, - userIdJsonV400, - List(AuthenticatedUserIsRequired, UnknownError), - List(apiTagUser) - ) - - lazy val getCurrentUserId: OBPEndpoint = { - case "users" :: "current" :: "user_id" :: Nil JsonGet _ => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - } yield { - ( - JSONFactory400.createUserIdInfoJson(u), - HttpCode.`200`(callContext) - ) - } - } - } - } - - staticResourceDocs += ResourceDoc( - getUserByUserId, - implementedInApiVersion, - nameOf(getUserByUserId), - "GET", - "/users/user_id/USER_ID", - "Get User by USER_ID", - s"""Get user by USER_ID - | - |${userAuthenticationMessage(true)} - |CanGetAnyUser entitlement is required, - | - """.stripMargin, - EmptyBody, - userJsonV400, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - UserNotFoundById, - UnknownError - ), - List(apiTagUser), - Some(List(canGetAnyUser)) - ) - - lazy val getUserByUserId: OBPEndpoint = { - case "users" :: "user_id" :: userId :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - user <- Users.users.vend.getUserByUserIdFuture(userId) map { x => - unboxFullOrFail( - x, - cc.callContext, - s"$UserNotFoundByUserId Current UserId($userId)" - ) - } - entitlements <- NewStyle.function.getEntitlementsByUserId( - user.userId, - cc.callContext - ) - acceptMarketingInfo <- NewStyle.function.getAgreementByUserId( - user.userId, - "accept_marketing_info", - cc.callContext - ) - termsAndConditions <- NewStyle.function.getAgreementByUserId( - user.userId, - "terms_and_conditions", - cc.callContext - ) - privacyConditions <- NewStyle.function.getAgreementByUserId( - user.userId, - "privacy_conditions", - cc.callContext - ) - isLocked = LoginAttempt.userIsLocked(user.provider, user.name) - } yield { - val agreements = - acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList - ( - JSONFactory400.createUserInfoJSON( - user, - entitlements, - Some(agreements), - isLocked - ), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserByUsername, - implementedInApiVersion, - nameOf(getUserByUsername), - "GET", - "/users/username/USERNAME", - "Get User by USERNAME", - s"""Get user by USERNAME - | - |${userAuthenticationMessage(true)} - | - |CanGetAnyUser entitlement is required, - | - """.stripMargin, - EmptyBody, - userJsonV400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UserNotFoundByProviderAndUsername, - UnknownError - ), - List(apiTagUser), - Some(List(canGetAnyUser)) - ) - - lazy val getUserByUsername: OBPEndpoint = { - case "users" :: "username" :: username :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - user <- Users.users.vend.getUserByProviderAndUsernameFuture( - Constant.localIdentityProvider, - username - ) map { x => - unboxFullOrFail( - x, - cc.callContext, - UserNotFoundByProviderAndUsername, - 404 - ) - } - entitlements <- NewStyle.function.getEntitlementsByUserId( - user.userId, - cc.callContext - ) - isLocked = LoginAttempt.userIsLocked(user.provider, user.name) - } yield { - ( - JSONFactory400.createUserInfoJSON( - user, - entitlements, - None, - isLocked - ), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUsersByEmail, - implementedInApiVersion, - nameOf(getUsersByEmail), - "GET", - "/users/email/USER_EMAIL/terminator", - "Get Users by Email Address", - s"""Get users by email address - | - |${userAuthenticationMessage(true)} - |CanGetAnyUser entitlement is required, - | - """.stripMargin, - EmptyBody, - usersJsonV400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UserNotFoundByEmail, - UnknownError - ), - List(apiTagUser), - Some(List(canGetAnyUser)) - ) - - lazy val getUsersByEmail: OBPEndpoint = { - case "users" :: "email" :: email :: "terminator" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - users <- Users.users.vend.getUsersByEmail(email) - } yield { - ( - JSONFactory400.createUsersJson(users), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUsers, - implementedInApiVersion, - nameOf(getUsers), - "GET", - "/users", - "Get all Users", - s"""Get all users - | - |${userAuthenticationMessage(true)} - | - |CanGetAnyUser entitlement is required, - | - |${urlParametersDocument(false, false)} - |* locked_status (if null ignore) - | - """.stripMargin, - EmptyBody, - usersJsonV400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canGetAnyUser)) - ) - - lazy val getUsers: OBPEndpoint = { - case "users" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) - (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture( - httpParams, - cc.callContext - ) - users <- Users.users.vend.getUsers(obpQueryParams) - } yield { - (JSONFactory400.createUsersJson(users), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createUserInvitation, - implementedInApiVersion, - nameOf(createUserInvitation), - "POST", - "/banks/BANK_ID/user-invitation", - "Create User Invitation", - s"""Create User Invitation. - | - | This endpoint will send an invitation email to the developers, then they can use the link to create the obp user. - | - | purpose filed only support:${UserInvitationPurpose.values - .toString()}. - | - | You can customise the email details use the following webui props: - | - | when purpose == ${UserInvitationPurpose.DEVELOPER.toString} - | webui_developer_user_invitation_email_subject - | webui_developer_user_invitation_email_from - | webui_developer_user_invitation_email_text - | webui_developer_user_invitation_email_html_text - | - | when purpose = == ${UserInvitationPurpose.CUSTOMER.toString} - | webui_customer_user_invitation_email_subject - | webui_customer_user_invitation_email_from - | webui_customer_user_invitation_email_text - | webui_customer_user_invitation_email_html_text - | - |""", - userInvitationPostJsonV400, - userInvitationJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagUserInvitation, apiTagKyc), - Some(canCreateUserInvitation :: Nil) - ) - - lazy val createUserInvitation: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user-invitation" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - logger.debug(s"Hello from the endpoint {$createUserInvitation}") - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostUserInvitationJsonV400 " - for { - postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostUserInvitationJsonV400] - } - - _ <- NewStyle.function.tryons( - s"$InvalidJsonValue postedData.purpose only support ${UserInvitationPurpose.values.toString()}", - 400, - cc.callContext - ) { - UserInvitationPurpose.withName(postedData.purpose) - } - - (invitation, callContext) <- NewStyle.function.createUserInvitation( - bankId, - postedData.first_name, - postedData.last_name, - postedData.email, - postedData.company, - postedData.country, - postedData.purpose, - cc.callContext - ) - } yield { - val link = - s"${APIUtil.getPropsValue("user_invitation_link_base_URL", APIUtil.getPropsValue("portal_hostname", Constant.HostName))}/user-invitation?id=${invitation.secretKey}" - if (postedData.purpose == UserInvitationPurpose.DEVELOPER.toString) { - val subject = getWebUiPropsValue( - "webui_developer_user_invitation_email_subject", - "Welcome to the API Playground" - ) - val from = getWebUiPropsValue( - "webui_developer_user_invitation_email_from", - "do-not-reply@openbankproject.com" - ) - val customText = getWebUiPropsValue( - "webui_developer_user_invitation_email_text", - DEFAULT_EMAIL_TEXT - ) - logger.debug(s"customText: ${customText}") - val customHtmlText = getWebUiPropsValue( - "webui_developer_user_invitation_email_html_text", - DEFAULT_EMAIL_HTML - ) - .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName) - .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link) - logger.debug(s"customHtmlText: ${customHtmlText}") - logger.debug( - s"Before send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}" - ) - - // Use Apache Commons Email wrapper instead of Lift Mailer - val emailContent = EmailContent( - from = from, - to = List(invitation.email), - subject = subject, - textContent = Some(customText), - htmlContent = Some(customHtmlText) - ) - - sendHtmlEmail(emailContent) match { - case Full(messageId) => - logger.debug( - s"Email sent successfully with Message-ID: $messageId" - ) - case Empty => logger.error("Failed to send user invitation email") - } - - logger.debug( - s"After send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}" - ) - } else { - val subject = getWebUiPropsValue( - "webui_customer_user_invitation_email_subject", - "Welcome to the API Playground" - ) - val from = getWebUiPropsValue( - "webui_customer_user_invitation_email_from", - "do-not-reply@openbankproject.com" - ) - val customText = getWebUiPropsValue( - "webui_customer_user_invitation_email_text", - DEFAULT_EMAIL_TEXT - ) - logger.debug(s"customText: ${customText}") - val customHtmlText = getWebUiPropsValue( - "webui_customer_user_invitation_email_html_text", - DEFAULT_EMAIL_HTML - ) - .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName) - .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link) - logger.debug(s"customHtmlText: ${customHtmlText}") - logger.debug(s"Before send user invitation by email.") - - // Use Apache Commons Email wrapper instead of Lift Mailer - val emailContent = EmailContent( - from = from, - to = List(invitation.email), - subject = subject, - textContent = Some(customText), - htmlContent = Some(customHtmlText) - ) - - sendHtmlEmail(emailContent) match { - case Full(messageId) => - logger.debug( - s"Email sent successfully with Message-ID: $messageId" - ) - case Empty => logger.error("Failed to send user invitation email") - } - - logger.debug(s"After send user invitation by email.") - } - ( - JSONFactory400.createUserInvitationJson(invitation), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserInvitationAnonymous, - implementedInApiVersion, - nameOf(getUserInvitationAnonymous), - "POST", - "/banks/BANK_ID/user-invitations", - "Get User Invitation Information", - s"""Get User Invitation Information. - | - |${userAuthenticationMessage(false)} - |""", - PostUserInvitationAnonymousJsonV400(secret_key = 5819479115482092878L), - userInvitationJsonV400, - List( - $BankNotFound, - UserCustomerLinksNotFoundForUser, - CannotGetUserInvitation, - CannotFindUserInvitation, - UnknownError - ), - List(apiTagUserInvitation, apiTagKyc) - ) - - lazy val getUserInvitationAnonymous: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user-invitations" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostUserInvitationAnonymousJsonV400 " - for { - postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostUserInvitationAnonymousJsonV400] - } - (invitation, callContext) <- NewStyle.function.getUserInvitation( - bankId, - postedData.secret_key, - cc.callContext - ) - _ <- Helper.booleanToFuture( - CannotFindUserInvitation, - 404, - cc.callContext - ) { - invitation.status == "CREATED" - } - _ <- Helper.booleanToFuture( - CannotFindUserInvitation, - 404, - cc.callContext - ) { - val validUntil = Calendar.getInstance - validUntil.setTime(invitation.createdAt.get) - validUntil.add(Calendar.HOUR, 24) - validUntil.getTime.after(new Date()) - } - } yield { - ( - JSONFactory400.createUserInvitationJson(invitation), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserInvitation, - implementedInApiVersion, - nameOf(getUserInvitation), - "GET", - "/banks/BANK_ID/user-invitations/SECRET_LINK", - "Get User Invitation", - s""" Get User Invitation - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - userInvitationJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagUserInvitation), - Some(List(canGetUserInvitation)) - ) - - lazy val getUserInvitation: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user-invitations" :: secretLink :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (invitation, callContext) <- NewStyle.function.getUserInvitation( - bankId, - secretLink.toLong, - cc.callContext - ) - } yield { - ( - JSONFactory400.createUserInvitationJson(invitation), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserInvitations, - implementedInApiVersion, - nameOf(getUserInvitations), - "GET", - "/banks/BANK_ID/user-invitations", - "Get User Invitations", - s""" Get User Invitations - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - userInvitationJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagUserInvitation), - Some(List(canGetUserInvitation)) - ) - - lazy val getUserInvitations: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "user-invitations" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (invitations, callContext) <- NewStyle.function.getUserInvitations( - bankId, - cc.callContext - ) - } yield { - ( - JSONFactory400.createUserInvitationJson(invitations), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteUser, - implementedInApiVersion, - nameOf(deleteUser), - "DELETE", - "/users/USER_ID", - "Delete a User", - s"""Delete a User. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagUser), - Some(List(canDeleteUser)) - ) - - lazy val deleteUser: OBPEndpoint = { - case "users" :: userId :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user, callContext) <- NewStyle.function.findByUserId( - userId, - cc.callContext - ) - (userDeleted, callContext) <- NewStyle.function.deleteUser( - user.userPrimaryKey, - callContext - ) - } yield { - (Full(userDeleted), HttpCode.`200`(callContext)) - } - } - } - - 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 (i.e. when connector=mapped in properties file) - |The settlement accounts are automatically created by the system when the bank is created. - |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) - | - |""", - postBankJson400, - bankJson400, - List( - InvalidJsonFormat, - $AuthenticatedUserIsRequired, - InsufficientAuthorisationToCreateBank, - UnknownError - ), - List(apiTagBank), - Some(List(canCreateBank)) - ) - - lazy val createBank: OBPEndpoint = { - case "banks" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $BankJson400 " - for { - bank <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[BankJson400] - } - _ <- Helper.booleanToFuture( - failMsg = ErrorMessages.InvalidConsumerCredentials, - cc = cc.callContext - ) { - cc.callContext.map(_.consumer.isDefined == true).isDefined - } - - checkShortStringValue = APIUtil.checkShortString(bank.id) - - _ <- Helper.booleanToFuture( - failMsg = s"$checkShortStringValue.", - cc = cc.callContext - ) { - checkShortStringValue == SILENCE_IS_GOLDEN - } - - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", - cc = cc.callContext - ) { - bank.id.length > 3 - } - - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidJsonFormat BANK_ID can not contain space characters", - cc = cc.callContext - ) { - !bank.id.contains(" ") - } - - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidJsonFormat BANK_ID can not contain `::::` characters", - cc = cc.callContext - ) { - !`checkIfContains::::`(bank.id) - } - - (success, callContext) <- NewStyle.function.createOrUpdateBank( - bank.id, - bank.full_name, - bank.short_name, - bank.logo, - bank.website, - bank.bank_routings - .find(_.scheme == "BIC") - .map(_.address) - .getOrElse(""), - "", - bank.bank_routings - .filterNot(_.scheme == "BIC") - .headOption - .map(_.scheme) - .getOrElse(""), - bank.bank_routings - .filterNot(_.scheme == "BIC") - .headOption - .map(_.address) - .getOrElse(""), - cc.callContext - ) - entitlements <- NewStyle.function.getEntitlementsByUserId( - cc.userId, - callContext - ) - entitlementsByBank = entitlements.filter(_.bankId == bank.id) - _ <- entitlementsByBank - .filter(_.roleName == CanCreateEntitlementAtOneBank.toString()) - .size > 0 match { - case true => - // Already has entitlement - Future() - case false => - Future( - Entitlement.entitlement.vend.addEntitlement( - bank.id, - 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, - cc.userId, - CanReadDynamicResourceDocsAtOneBank.toString() - ) - ) - } - } yield { - ( - JSONFactory400.createBankJSON400(success), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createDirectDebit, - implementedInApiVersion, - nameOf(createDirectDebit), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/direct-debit", - "Create Direct Debit", - s"""Create direct debit for an account. - | - |""", - postDirectDebitJsonV400, - directDebitJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - NoViewPermission, - $UserNoPermissionAccessView, - InvalidJsonFormat, - CustomerNotFoundByCustomerId, - UserNotFoundByUserId, - CounterpartyNotFoundByCounterpartyId, - UnknownError - ), - List(apiTagDirectDebit, apiTagAccount) - ) - - lazy val createDirectDebit: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "direct-debit" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = - s"$NoViewPermission can_create_direct_debit. Current ViewId($viewId)", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_CREATE_DIRECT_DEBIT) - } - failMsg = - s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostDirectDebitJsonV400] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId( - postJson.customer_id, - callContext - ) - _ <- Users.users.vend - .getUserByUserIdFuture(postJson.user_id) map { x => - unboxFullOrFail( - x, - callContext, - s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" - ) - } - (_, callContext) <- NewStyle.function - .getCounterpartyByCounterpartyId( - CounterpartyId(postJson.counterparty_id), - callContext - ) - (directDebit, callContext) <- NewStyle.function.createDirectDebit( - bankId.value, - accountId.value, - postJson.customer_id, - postJson.user_id, - postJson.counterparty_id, - if (postJson.date_signed.isDefined) postJson.date_signed.get - else new Date(), - postJson.date_starts, - postJson.date_expires, - callContext - ) - } yield { - ( - JSONFactory400.createDirectDebitJSON(directDebit), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createDirectDebitManagement, - implementedInApiVersion, - nameOf(createDirectDebitManagement), - "POST", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/direct-debit", - "Create Direct Debit (management)", - s"""Create direct debit for an account. - | - |""", - postDirectDebitJsonV400, - directDebitJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - NoViewPermission, - InvalidJsonFormat, - CustomerNotFoundByCustomerId, - UserNotFoundByUserId, - CounterpartyNotFoundByCounterpartyId, - UnknownError - ), - List(apiTagDirectDebit, apiTagAccount), - Some(List(canCreateDirectDebitAtOneBank)) - ) - - lazy val createDirectDebitManagement: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "direct-debit" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 " - for { - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostDirectDebitJsonV400] - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId( - postJson.customer_id, - cc.callContext - ) - _ <- Users.users.vend - .getUserByUserIdFuture(postJson.user_id) map { x => - unboxFullOrFail( - x, - callContext, - s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" - ) - } - (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId( - CounterpartyId(postJson.counterparty_id), - callContext - ) - (directDebit, callContext) <- NewStyle.function.createDirectDebit( - bankId.value, - accountId.value, - postJson.customer_id, - postJson.user_id, - postJson.counterparty_id, - if (postJson.date_signed.isDefined) postJson.date_signed.get - else new Date(), - postJson.date_starts, - postJson.date_expires, - callContext - ) - } yield { - ( - JSONFactory400.createDirectDebitJSON(directDebit), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createStandingOrder, - implementedInApiVersion, - nameOf(createStandingOrder), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/standing-order", - "Create Standing Order", - s"""Create standing order for an account. - | - |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’} - |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}} - | - |""", - postStandingOrderJsonV400, - standingOrderJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - NoViewPermission, - InvalidJsonFormat, - InvalidNumber, - InvalidISOCurrencyCode, - CustomerNotFoundByCustomerId, - UserNotFoundByUserId, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagStandingOrder, apiTagAccount) - ) - - lazy val createStandingOrder: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "standing-order" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = - s"$NoViewPermission can_create_standing_order. Current ViewId($viewId)", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_CREATE_STANDING_ORDER) - } - failMsg = - s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PostStandingOrderJsonV400] - } - amountValue <- NewStyle.function.tryons( - s"$InvalidNumber Current input is ${postJson.amount.amount} ", - 400, - callContext - ) { - BigDecimal(postJson.amount.amount) - } - _ <- Helper.booleanToFuture( - s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'", - cc = callContext - ) { - APIUtil.isValidCurrencyISOCode(postJson.amount.currency) - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId( - postJson.customer_id, - callContext - ) - _ <- Users.users.vend - .getUserByUserIdFuture(postJson.user_id) map { x => - unboxFullOrFail( - x, - callContext, - s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" - ) - } - (_, callContext) <- NewStyle.function - .getCounterpartyByCounterpartyId( - CounterpartyId(postJson.counterparty_id), - callContext - ) - (directDebit, callContext) <- NewStyle.function.createStandingOrder( - bankId.value, - accountId.value, - postJson.customer_id, - postJson.user_id, - postJson.counterparty_id, - amountValue, - postJson.amount.currency, - postJson.when.frequency, - postJson.when.detail, - if (postJson.date_signed.isDefined) postJson.date_signed.get - else new Date(), - postJson.date_starts, - postJson.date_expires, - callContext - ) - } yield { - ( - JSONFactory400.createStandingOrderJSON(directDebit), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createStandingOrderManagement, - implementedInApiVersion, - nameOf(createStandingOrderManagement), - "POST", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/standing-order", - "Create Standing Order (management)", - s"""Create standing order for an account. - | - |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’} - |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}} - | - | - |""", - postStandingOrderJsonV400, - standingOrderJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - NoViewPermission, - InvalidJsonFormat, - InvalidNumber, - InvalidISOCurrencyCode, - CustomerNotFoundByCustomerId, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagStandingOrder, apiTagAccount), - Some(List(canCreateStandingOrderAtOneBank)) - ) - - lazy val createStandingOrderManagement: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "standing-order" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 " - for { - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostStandingOrderJsonV400] - } - amountValue <- NewStyle.function.tryons( - s"$InvalidNumber Current input is ${postJson.amount.amount} ", - 400, - cc.callContext - ) { - BigDecimal(postJson.amount.amount) - } - _ <- Helper.booleanToFuture( - s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'", - cc = cc.callContext - ) { - APIUtil.isValidCurrencyISOCode(postJson.amount.currency) - } - (_, callContext) <- NewStyle.function.getCustomerByCustomerId( - postJson.customer_id, - cc.callContext - ) - _ <- Users.users.vend - .getUserByUserIdFuture(postJson.user_id) map { x => - unboxFullOrFail( - x, - callContext, - s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" - ) - } - (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId( - CounterpartyId(postJson.counterparty_id), - callContext - ) - (directDebit, callContext) <- NewStyle.function.createStandingOrder( - bankId.value, - accountId.value, - postJson.customer_id, - postJson.user_id, - postJson.counterparty_id, - amountValue, - postJson.amount.currency, - postJson.when.frequency, - postJson.when.detail, - if (postJson.date_signed.isDefined) postJson.date_signed.get - else new Date(), - postJson.date_starts, - postJson.date_expires, - callContext - ) - } yield { - ( - JSONFactory400.createStandingOrderJSON(directDebit), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - grantUserAccessToView, - implementedInApiVersion, - "grantUserAccessToView", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/grant", - "Grant User access to View", - s"""Grants the User identified by USER_ID access to the view identified by VIEW_ID. - | - |${userAuthenticationMessage( - true - )} and the user needs to be account holder. - | - |""", - postAccountAccessJsonV400, - viewJsonV300, - List( - $AuthenticatedUserIsRequired, - UserLacksPermissionCanGrantAccessToViewForTargetAccount, - InvalidJsonFormat, - UserNotFoundById, - SystemViewNotFound, - ViewNotFound, - CannotGrantAccountAccess, - UnknownError - ), - List( - apiTagAccountAccess, - apiTagView, - apiTagAccount, - apiTagUser, - apiTagOwnerRequired - ) - ) - - lazy val grantUserAccessToView: OBPEndpoint = { - // add access for specific user to a specific system view - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "account-access" :: "grant" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " - for { - (Full(u), callContext) <- SS.user - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostAccountAccessJsonV400] - } - msg = - UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${postJson.view.view_id}) and current UserId(${u.userId})" - _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { - APIUtil.canGrantAccessToView( - bankId, - accountId, - ViewId(postJson.view.view_id), - u, - callContext - ) - } - (user, callContext) <- NewStyle.function.findByUserId( - postJson.user_id, - callContext - ) - view <- getView(bankId, accountId, postJson.view, callContext) - addedView <- grantAccountAccessToUser( - bankId, - accountId, - user, - view, - callContext - ) - } yield { - val viewJson = JSONFactory300.createViewJSON(addedView) - (viewJson, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createUserWithAccountAccess, - implementedInApiVersion, - nameOf(createUserWithAccountAccess), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/user-account-access", - "Create (DAuth) User with Account Access", - s"""This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain. - | - |Put the smart contract address in username - | - |For provider use "dauth" - | - |This endpoint will create the (DAuth) User with username and provider if the User does not already exist. - | - |${userAuthenticationMessage( - true - )} and the logged in user needs to be account holder. - | - |For information about DAuth see below: - | - |${getGlossaryItem("DAuth")} - | - |""", - postCreateUserAccountAccessJsonV400, - List(viewJsonV300), - List( - $AuthenticatedUserIsRequired, - UserLacksPermissionCanGrantAccessToViewForTargetAccount, - InvalidJsonFormat, - SystemViewNotFound, - ViewNotFound, - CannotGrantAccountAccess, - UnknownError - ), - List( - apiTagAccountAccess, - apiTagView, - apiTagAccount, - apiTagUser, - apiTagOwnerRequired, - apiTagDAuth - ) - ) - - lazy val createUserWithAccountAccess: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "user-account-access" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostCreateUserAccountAccessJsonV400 " - for { - (Full(u), callContext) <- SS.user - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostCreateUserAccountAccessJsonV400] - } - // provider must start with dauth., can not create other provider users. - _ <- Helper.booleanToFuture( - s"$InvalidUserProvider The user.provider must be start with 'dauth.'", - cc = Some(cc) - ) { - postJson.provider.startsWith("dauth.") - } - viewIdList = postJson.views.map(view => ViewId(view.view_id)) - msg = - UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${viewIdList.mkString}) and current UserId(${u.userId})" - _ <- Helper.booleanToFuture(msg, 403, cc = Some(cc)) { - APIUtil.canGrantAccessToMultipleViews( - bankId, - accountId, - viewIdList, - u, - callContext - ) - } - (targetUser, callContext) <- NewStyle.function - .getOrCreateResourceUser( - postJson.provider, - postJson.username, - cc.callContext - ) - views <- getViews(bankId, accountId, postJson, callContext) - addedView <- grantMultpleAccountAccessToUser( - bankId, - accountId, - targetUser, - views, - callContext - ) - } yield { - val viewsJson = addedView.map(JSONFactory300.createViewJSON(_)) - (viewsJson, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - revokeUserAccessToView, - implementedInApiVersion, - "revokeUserAccessToView", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/revoke", - "Revoke User access to View", - s"""Revoke the User identified by USER_ID access to the view identified by VIEW_ID. - | - |${userAuthenticationMessage( - true - )} and the user needs to be account holder. - | - |""", - postAccountAccessJsonV400, - revokedJsonV400, - List( - $AuthenticatedUserIsRequired, - UserLacksPermissionCanRevokeAccessToViewForTargetAccount, - InvalidJsonFormat, - UserNotFoundById, - SystemViewNotFound, - ViewNotFound, - CannotRevokeAccountAccess, - CannotFindAccountAccess, - UnknownError - ), - List( - apiTagAccountAccess, - apiTagView, - apiTagAccount, - apiTagUser, - apiTagOwnerRequired - ) - ) - - lazy val revokeUserAccessToView: OBPEndpoint = { - // add access for specific user to a specific system view - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "account-access" :: "revoke" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " - for { - (Full(u), callContext) <- SS.user - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostAccountAccessJsonV400] - } - viewId = ViewId(postJson.view.view_id) - msg = - UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${viewId}) and current UserId(${u.userId})" - _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { - APIUtil.canRevokeAccessToView( - bankId, - accountId, - viewId, - u, - callContext - ) - } - (user, callContext) <- NewStyle.function.findByUserId( - postJson.user_id, - cc.callContext - ) - view <- postJson.view.is_system match { - case true => ViewNewStyle.systemView(viewId, callContext) - case false => - ViewNewStyle.customView( - viewId, - BankIdAccountId(bankId, accountId), - callContext - ) - } - revoked <- postJson.view.is_system match { - case true => - ViewNewStyle.revokeAccessToSystemView( - bankId, - accountId, - view, - user, - callContext - ) - case false => - ViewNewStyle.revokeAccessToCustomView(view, user, callContext) - } - } yield { - (RevokedJsonV400(revoked), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - revokeGrantUserAccessToViews, - implementedInApiVersion, - "revokeGrantUserAccessToViews", - "PUT", - "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access", - "Revoke/Grant User access to View", - s"""Revoke/Grant the logged in User access to the views identified by json. - | - |${userAuthenticationMessage( - true - )} and the user needs to be an account holder or has owner view access. - | - |""", - postRevokeGrantAccountAccessJsonV400, - revokedJsonV400, - List( - $AuthenticatedUserIsRequired, - UserLacksPermissionCanGrantAccessToViewForTargetAccount, - InvalidJsonFormat, - UserNotFoundById, - SystemViewNotFound, - ViewNotFound, - CannotRevokeAccountAccess, - CannotFindAccountAccess, - UnknownError - ), - List( - apiTagAccountAccess, - apiTagView, - apiTagAccount, - apiTagUser, - apiTagOwnerRequired - ) - ) - - lazy val revokeGrantUserAccessToViews: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "account-access" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " - for { - (Full(u), callContext) <- SS.user - postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[PostRevokeGrantAccountAccessJsonV400] - } - msg = - UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${postJson.views.mkString}) and current UserId(${u.userId})" - _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { - APIUtil.canRevokeAccessToAllViews(bankId, accountId, u, callContext) - } - _ <- Future( - Views.views.vend - .revokeAccountAccessByUser(bankId, accountId, u, callContext) - ) map { - unboxFullOrFail(_, callContext, s"Cannot revoke") - } - grantViews = for (viewId <- postJson.views) - yield BankIdAccountIdViewId(bankId, accountId, ViewId(viewId)) - _ <- Future( - Views.views.vend - .grantAccessToMultipleViews(grantViews, u, callContext) - ) map { - unboxFullOrFail( - _, - callContext, - s"Cannot grant the views: ${postJson.views.mkString(",")}" - ) - } - } yield { - (RevokedJsonV400(true), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createCustomerAttribute, - implementedInApiVersion, - nameOf(createCustomerAttribute), - "POST", - "/banks/BANK_ID/customers/CUSTOMER_ID/attribute", - "Create Customer Attribute", - s""" Create Customer Attribute - | - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - customerAttributeJsonV400, - customerAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some( - List( - canCreateCustomerAttributeAtOneBank, - canCreateCustomerAttributeAtAnyBank - ) - ) - ) - - lazy val createCustomerAttribute: OBPEndpoint = { - case "banks" :: bankId :: "customers" :: customerId :: "attribute" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[CustomerAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)" - customerAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - CustomerAttributeType.withName(postedData.`type`) - } - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, cc.callContext) - _ <- Helper.booleanToFuture( - InvalidCustomerBankId - .replaceAll("Bank Id.", s"Bank Id ($bankId).") - .replaceAll("The Customer", s"The Customer($customerId)"), - cc = callContext - ) { customer.bankId == bankId } - (accountAttribute, callContext) <- NewStyle.function - .createOrUpdateCustomerAttribute( - BankId(bankId), - CustomerId(customerId), - None, - postedData.name, - customerAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createCustomerAttributeJson(accountAttribute), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateCustomerAttribute, - implementedInApiVersion, - nameOf(updateCustomerAttribute), - "PUT", - "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID", - "Update Customer Attribute", - s""" Update Customer Attribute - | - | - |${userAuthenticationMessage(true)} - | - |""", - customerAttributeJsonV400, - customerAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some( - List( - canUpdateCustomerAttributeAtOneBank, - canUpdateCustomerAttributeAtAnyBank - ) - ) - ) - - lazy val updateCustomerAttribute: OBPEndpoint = { - case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400" - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[CustomerAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)" - customerAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - CustomerAttributeType.withName(postedData.`type`) - } - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, cc.callContext) - _ <- Helper.booleanToFuture( - InvalidCustomerBankId - .replaceAll("Bank Id.", s"Bank Id ($bankId).") - .replaceAll("The Customer", s"The Customer($customerId)"), - cc = callContext - ) { customer.bankId == bankId } - (accountAttribute, callContext) <- NewStyle.function - .getCustomerAttributeById( - customerAttributeId, - callContext - ) - (accountAttribute, callContext) <- NewStyle.function - .createOrUpdateCustomerAttribute( - BankId(bankId), - CustomerId(customerId), - Some(customerAttributeId), - postedData.name, - customerAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createCustomerAttributeJson(accountAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomerAttributes, - implementedInApiVersion, - nameOf(getCustomerAttributes), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/attributes", - "Get Customer Attributes", - s""" Get Customer Attributes - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some( - List( - canGetCustomerAttributesAtOneBank, - canGetCustomerAttributesAtAnyBank - ) - ) - ) - - lazy val getCustomerAttributes: OBPEndpoint = { - case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, cc.callContext) - _ <- Helper.booleanToFuture( - InvalidCustomerBankId - .replaceAll("Bank Id.", s"Bank Id ($bankId).") - .replaceAll("The Customer", s"The Customer($customerId)"), - cc = callContext - ) { customer.bankId == bankId } - (accountAttribute, callContext) <- NewStyle.function - .getCustomerAttributes( - BankId(bankId), - CustomerId(customerId), - callContext - ) - } yield { - ( - JSONFactory400.createCustomerAttributesJson(accountAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomerAttributeById, - implementedInApiVersion, - nameOf(getCustomerAttributeById), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/ATTRIBUTE_ID", - "Get Customer Attribute By Id", - s""" Get Customer Attribute By Id - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some( - List(canGetCustomerAttributeAtOneBank, canGetCustomerAttributeAtAnyBank) - ) - ) - - lazy val getCustomerAttributeById: OBPEndpoint = { - case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, cc.callContext) - _ <- Helper.booleanToFuture( - InvalidCustomerBankId - .replaceAll("Bank Id.", s"Bank Id ($bankId).") - .replaceAll("The Customer", s"The Customer($customerId)"), - cc = callContext - ) { customer.bankId == bankId } - (accountAttribute, callContext) <- NewStyle.function - .getCustomerAttributeById( - customerAttributeId, - callContext - ) - } yield { - ( - JSONFactory400.createCustomerAttributeJson(accountAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomersByAttributes, - implementedInApiVersion, - nameOf(getCustomersByAttributes), - "GET", - "/banks/BANK_ID/customers", - "Get Customers by ATTRIBUTES", - s"""Gets the Customers specified by attributes - | - |URL params example: /banks/some-bank-id/customers?name=John&age=8 - |URL params example: /banks/some-bank-id/customers?&limit=50&offset=1 - | - | - |""", - EmptyBody, - ListResult( - "customers", - List(customerWithAttributesJsonV310) - ), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer), - Some(List(canGetCustomersAtOneBank)) - ) - - lazy val getCustomersByAttributes: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (customerIds, callContext) <- NewStyle.function - .getCustomerIdsByAttributeNameValues(bankId, req.params, Some(cc)) - list: List[CustomerWithAttributesJsonV310] <- { - val listCustomerFuture - : List[Future[CustomerWithAttributesJsonV310]] = - customerIds.map { customerId => - val customerFuture = NewStyle.function - .getCustomerByCustomerId(customerId.value, callContext) - customerFuture.flatMap { customerAndCc => - val (customer, cc) = customerAndCc - NewStyle.function - .getCustomerAttributes(bankId, customerId, cc) - .map { attributesAndCc => - val (attributes, _) = attributesAndCc - JSONFactory310.createCustomerWithAttributesJson( - customer, - attributes - ) - } - } - } - Future.sequence(listCustomerFuture) - } - } yield { - (ListResult("customers", list), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createTransactionAttribute, - implementedInApiVersion, - nameOf(createTransactionAttribute), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attribute", - "Create Transaction Attribute", - s""" Create Transaction Attribute - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - transactionAttributeJsonV400, - transactionAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canCreateTransactionAttributeAtOneBank)) - ) - - lazy val createTransactionAttribute: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transactions" :: TransactionId( - transactionId - ) :: "attribute" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400 " - for { - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[TransactionAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)" - transactionAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - TransactionAttributeType.withName(postedData.`type`) - } - (accountAttribute, callContext) <- NewStyle.function - .createOrUpdateTransactionAttribute( - bankId, - transactionId, - None, - postedData.name, - transactionAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionAttributeJson(accountAttribute), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateTransactionAttribute, - implementedInApiVersion, - nameOf(updateTransactionAttribute), - "PUT", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ACCOUNT_ATTRIBUTE_ID", - "Update Transaction Attribute", - s""" Update Transaction Attribute - | - | - |${userAuthenticationMessage(true)} - | - |""", - transactionAttributeJsonV400, - transactionAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canUpdateTransactionAttributeAtOneBank)) - ) - - lazy val updateTransactionAttribute: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transactions" :: TransactionId( - transactionId - ) :: "attributes" :: transactionAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400" - for { - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[TransactionAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)" - transactionAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - TransactionAttributeType.withName(postedData.`type`) - } - (_, callContext) <- NewStyle.function.getTransactionAttributeById( - transactionAttributeId, - callContext - ) - (transactionAttribute, callContext) <- NewStyle.function - .createOrUpdateTransactionAttribute( - bankId, - transactionId, - Some(transactionAttributeId), - postedData.name, - transactionAttributeType, - postedData.value, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionAttributeJson( - transactionAttribute - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionAttributes, - implementedInApiVersion, - nameOf(getTransactionAttributes), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes", - "Get Transaction Attributes", - s""" Get Transaction Attributes - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canGetTransactionAttributesAtOneBank)) - ) - - lazy val getTransactionAttributes: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transactions" :: TransactionId( - transactionId - ) :: "attributes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - (accountAttribute, callContext) <- NewStyle.function - .getTransactionAttributes( - bankId, - transactionId, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionAttributesJson(accountAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionAttributeById, - implementedInApiVersion, - nameOf(getTransactionAttributeById), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ATTRIBUTE_ID", - "Get Transaction Attribute By Id", - s""" Get Transaction Attribute By Id - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canGetTransactionAttributeAtOneBank)) - ) - - lazy val getTransactionAttributeById: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: "transactions" :: TransactionId( - transactionId - ) :: "attributes" :: transactionAttributeId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - (accountAttribute, callContext) <- NewStyle.function - .getTransactionAttributeById( - transactionAttributeId, - callContext - ) - } yield { - ( - JSONFactory400.createTransactionAttributeJson(accountAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createHistoricalTransactionAtBank, - implementedInApiVersion, - nameOf(createHistoricalTransactionAtBank), - "POST", - "/banks/BANK_ID/management/historical/transactions", - "Create Historical Transactions ", - s""" - |Create historical transactions at one Bank - | - |Use this endpoint to create transactions between any two accounts at the same bank. - |From account and to account must be at the same bank. - |Example: - |{ - | "from_account_id": "1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", - | "to_account_id": "2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", - | "value": { - | "currency": "GBP", - | "amount": "10" - | }, - | "description": "this is for work", - | "posted": "2017-09-19T02:31:05Z", - | "completed": "2017-09-19T02:31:05Z", - | "type": "SANDBOX_TAN", - | "charge_policy": "SHARED" - |} - | - |This call is experimental. - """.stripMargin, - postHistoricalTransactionAtBankJson, - postHistoricalTransactionResponseJson, - List( - InvalidJsonFormat, - BankNotFound, - AccountNotFound, - CounterpartyNotFoundByCounterpartyId, - InvalidNumber, - NotPositiveAmount, - InvalidTransactionRequestCurrency, - UnknownError - ), - List(apiTagTransactionRequest), - Some(List(canCreateHistoricalTransactionAtBank)) - ) - - lazy val createHistoricalTransactionAtBank: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "management" :: "historical" :: "transactions" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId.value, - u.userId, - ApiRole.canCreateHistoricalTransactionAtBank, - callContext - ) - - // Check the input JSON format, here is just check the common parts of all four types - transDetailsJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostHistoricalTransactionJson ", - 400, - callContext - ) { - json.extract[PostHistoricalTransactionAtBankJson] - } - (fromAccount, callContext) <- NewStyle.function - .checkBankAccountExists( - bankId, - AccountId(transDetailsJson.from_account_id), - callContext - ) - (toAccount, callContext) <- NewStyle.function - .checkBankAccountExists( - bankId, - AccountId(transDetailsJson.to_account_id), - callContext - ) - amountNumber <- NewStyle.function.tryons( - s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", - 400, - callContext - ) { - BigDecimal(transDetailsJson.value.amount) - } - _ <- Helper.booleanToFuture( - s"${NotPositiveAmount} Current input is: '${amountNumber}'", - cc = callContext - ) { - amountNumber > BigDecimal("0") - } - posted <- NewStyle.function.tryons( - s"$InvalidDateFormat Current `posted` field is ${transDetailsJson.posted}. Please use this format ${DateWithSecondsFormat.toPattern}! ", - 400, - callContext - ) { - new SimpleDateFormat(DateWithSeconds).parse( - transDetailsJson.posted - ) - } - completed <- NewStyle.function.tryons( - s"$InvalidDateFormat Current `completed` field is ${transDetailsJson.completed}. Please use this format ${DateWithSecondsFormat.toPattern}! ", - 400, - callContext - ) { - new SimpleDateFormat(DateWithSeconds).parse( - transDetailsJson.completed - ) - } - // Prevent default value for transaction request type (at least). - _ <- Helper.booleanToFuture( - s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", - cc = callContext - ) { - APIUtil.isValidCurrencyISOCode(transDetailsJson.value.currency) - } - amountOfMoneyJson = AmountOfMoneyJsonV121( - transDetailsJson.value.currency, - transDetailsJson.value.amount - ) - chargePolicy = transDetailsJson.charge_policy - // There is no constraint for the type at the moment - transactionType = transDetailsJson.`type` - (transactionId, callContext) <- NewStyle.function - .makeHistoricalPayment( - fromAccount, - toAccount, - posted, - completed, - amountNumber, - transDetailsJson.value.currency, - transDetailsJson.description, - transactionType, - chargePolicy, - callContext - ) - } yield { - ( - JSONFactory400.createPostHistoricalTransactionResponseJson( - bankId, - transactionId, - fromAccount.accountId, - toAccount.accountId, - value = amountOfMoneyJson, - description = transDetailsJson.description, - posted, - completed, - transactionRequestType = transactionType, - chargePolicy = transDetailsJson.charge_policy - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionRequest, - implementedInApiVersion, - nameOf(getTransactionRequest), - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests/TRANSACTION_REQUEST_ID", - "Get Transaction Request.", - """Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID and for account specified by ACCOUNT_ID at bank specified by BANK_ID. - | - |The VIEW_ID specified must be 'owner' and the user must have access to this view. - | - |Version 2.0.0 now returns charge information. - | - |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including: - | - |* Transaction Request Id - |* Type - |* Status (INITIATED, COMPLETED) - |* Challenge (in order to confirm the request) - |* From Bank / Account - |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.) - |* Related Transactions - | - |PSD2 Context: PSD2 requires transparency of charges to the customer. - |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after. - |The customer can proceed with the Transaction by answering the security challenge. - | - """.stripMargin, - EmptyBody, - transactionRequestWithChargeJSON210, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - GetTransactionRequestsException, - UnknownError - ), - List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) - ) - - lazy val getTransactionRequest: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "transaction-requests" :: TransactionRequestId( - requestId - ) :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- NewStyle.function.isEnabledTransactionRequests(callContext) - view <- ViewNewStyle.checkAccountAccessAndGetView( - viewId, - BankIdAccountId(bankId, accountId), - Full(u), - callContext - ) - _ <- Helper.booleanToFuture( - s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})", - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_SEE_TRANSACTION_REQUESTS) - } - (transactionRequest, callContext) <- NewStyle.function - .getTransactionRequestImpl(requestId, callContext) - } yield { - val json = JSONFactory210.createTransactionRequestWithChargeJSON( - transactionRequest - ) - (json, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getPrivateAccountsAtOneBank, - implementedInApiVersion, - "getPrivateAccountsAtOneBank", - "GET", - "/banks/BANK_ID/accounts", - "Get Accounts at Bank", - s""" - |Returns the list of accounts at BANK_ID that the user has access to. - |For each account the API returns the account ID and the views available to the user.. - |Each account must have at least one private View. - | - |optional request parameters for filter with attributes - |URL params example: /banks/some-bank-id/accounts?&limit=50&offset=1 - | - | - """.stripMargin, - EmptyBody, - basicAccountsJSON, - List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError), - List(apiTagAccount, apiTagPrivateData, apiTagPublicData) - ) - - lazy val getPrivateAccountsAtOneBank: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), bank, callContext) <- SS.userBank - (privateViewsUserCanAccessAtOneBank, privateAccountAccess) = - Views.views.vend.privateViewsUserCanAccessAtBank(u, bankId) - params = req.params - .filterNot( - _._1 == PARAM_TIMESTAMP - ) // ignore `_timestamp_` parameter, it is for invalid Browser caching - .filterNot(_._1 == PARAM_LOCALE) - privateAccountAccess2 <- - if (params.isEmpty || privateAccountAccess.isEmpty) { - Future.successful(privateAccountAccess) - } else { - AccountAttributeX.accountAttributeProvider.vend - .getAccountIdsByParams(bankId, params) - .map { boxedAccountIds => - val accountIds = boxedAccountIds.getOrElse(Nil) - privateAccountAccess.filter(aa => - accountIds.contains(aa.account_id.get) - ) - } - } - (availablePrivateAccounts, callContext) <- bank.privateAccountsFuture( - privateAccountAccess2, - callContext - ) - } yield { - val bankAccounts = Implementations2_0_0.processAccounts( - privateViewsUserCanAccessAtOneBank, - availablePrivateAccounts - ) - (bankAccounts, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createConsumer, - implementedInApiVersion, - "createConsumer", - "POST", - "/management/consumers", - "Post a Consumer", - s"""Create a Consumer (Authenticated access). - | - |""", - ConsumerPostJSON( - "Test", - "Web", - "Description", - "some@email.com", - "redirecturl", - "createdby", - true, - new Date(), - """-----BEGIN CERTIFICATE----- - |client_certificate_content - |-----END CERTIFICATE-----""".stripMargin - ), - consumerJsonV400, - List( - AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagConsumer), - Some(List(canCreateConsumer)) - ) - - lazy val createConsumer: OBPEndpoint = { - case "management" :: "consumers" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - (postedJson, appType) <- NewStyle.function.tryons( - InvalidJsonFormat, - 400, - callContext - ) { - val consumerPostJSON = json.extract[ConsumerPostJSON] - val appType = - if (consumerPostJSON.app_type.equals("Confidential")) - AppType.valueOf("Confidential") - else AppType.valueOf("Public") - (consumerPostJSON, appType) - } - _ <- NewStyle.function.hasEntitlement( - "", - u.userId, - ApiRole.canCreateConsumer, - callContext - ) - (consumer, callContext) <- createConsumerNewStyle( - key = Some(Helpers.randomString(40).toLowerCase), - secret = Some(Helpers.randomString(40).toLowerCase), - isActive = Some(postedJson.enabled), - name = Some(postedJson.app_name), - appType = Some(appType), - description = Some(postedJson.description), - developerEmail = Some(postedJson.developer_email), - company = None, - redirectURL = Some(postedJson.redirect_url), - createdByUserId = Some(u.userId), - clientCertificate = Some(postedJson.clientCertificate), - logoURL = None, - callContext - ) - user <- Users.users.vend.getUserByUserIdFuture(u.userId) - } yield { - // Format the data as json - val json = JSONFactory400.createConsumerJSON(consumer, user) - // Return - (json, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomersAtAnyBank, - implementedInApiVersion, - nameOf(getCustomersAtAnyBank), - "GET", - "/customers", - "Get Customers at Any Bank", - s"""Get Customers at Any Bank. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customersJsonV300, - List( - AuthenticatedUserIsRequired, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer, apiTagUser), - Some(List(canGetCustomersAtAllBanks)) - ) - lazy val getCustomersAtAnyBank: OBPEndpoint = { - case "customers" :: Nil JsonGet _ => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (requestParams, callContext) <- extractQueryParams( - cc.url, - List("limit", "offset", "sort_direction"), - cc.callContext - ) - (customers, callContext) <- getCustomersAtAllBanks( - callContext, - requestParams - ) - } yield { - ( - JSONFactory300.createCustomersJson(customers.sortBy(_.bankId)), - HttpCode.`200`(callContext) - ) - } - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomersMinimalAtAnyBank, - implementedInApiVersion, - nameOf(getCustomersMinimalAtAnyBank), - "GET", - "/customers-minimal", - "Get Customers Minimal at Any Bank", - s"""Get Customers Minimal at Any Bank. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customersMinimalJsonV300, - List( - AuthenticatedUserIsRequired, - UserCustomerLinksNotFoundForUser, - UnknownError - ), - List(apiTagCustomer, apiTagUser), - Some(List(canGetCustomersMinimalAtAllBanks)) - ) - lazy val getCustomersMinimalAtAnyBank: OBPEndpoint = { - case "customers-minimal" :: Nil JsonGet _ => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (requestParams, callContext) <- extractQueryParams( - cc.url, - List("limit", "offset", "sort_direction"), - cc.callContext - ) - (customers, callContext) <- getCustomersAtAllBanks( - callContext, - requestParams - ) - } yield { - ( - createCustomersMinimalJson(customers.sortBy(_.bankId)), - HttpCode.`200`(callContext) - ) - } - } - } - } - - staticResourceDocs += ResourceDoc( - getScopes, - implementedInApiVersion, - nameOf(getScopes), - "GET", - "/consumers/CONSUMER_ID/scopes", - "Get Scopes for Consumer", - s"""Get all the scopes for an consumer specified by CONSUMER_ID - | - |${userAuthenticationMessage(true)} - | - | - """.stripMargin, - EmptyBody, - scopeJsons, - List( - AuthenticatedUserIsRequired, - EntitlementNotFound, - ConsumerNotFoundByConsumerId, - UnknownError - ), - List(apiTagScope, apiTagConsumer) - ) - - lazy val getScopes: OBPEndpoint = { - case "consumers" :: uuidOfConsumer :: "scopes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - consumer <- Future { callContext.get.consumer } map { x => - unboxFullOrFail(x, callContext, InvalidConsumerCredentials) - } - _ <- Future { - NewStyle.function.hasEntitlementAndScope( - "", - u.userId, - consumer.id.get.toString, - canGetEntitlementsForAnyUserAtAnyBank, - callContext - ) - } flatMap { unboxFullAndWrapIntoFuture(_) } - consumer <- NewStyle.function.getConsumerByConsumerId( - uuidOfConsumer, - callContext - ) - primaryKeyOfConsumer = consumer.id.get.toString - scopes <- Future { - Scope.scope.vend.getScopesByConsumerId(primaryKeyOfConsumer) - } map { unboxFull(_) } - } yield ( - JSONFactory300.createScopeJSONs(scopes), - HttpCode.`200`(callContext) - ) - } - } - - staticResourceDocs += ResourceDoc( - addScope, - implementedInApiVersion, - nameOf(addScope), - "POST", - "/consumers/CONSUMER_ID/scopes", - "Create Scope for a Consumer", - """Create Scope. Grant Role to Consumer. - | - |Scopes are used to grant System or Bank level roles to the Consumer (App). (For Account level privileges, see Views) - | - |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":"" - | - |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id" - | - |""", - SwaggerDefinitionsJSON.createScopeJson, - scopeJson, - List( - AuthenticatedUserIsRequired, - ConsumerNotFoundById, - InvalidJsonFormat, - IncorrectRoleName, - EntitlementIsBankRole, - EntitlementIsSystemRole, - EntitlementAlreadyExists, - UnknownError - ), - List(apiTagScope, apiTagConsumer), - Some(List(canCreateScopeAtAnyBank, canCreateScopeAtOneBank)) - ) - - lazy val addScope: OBPEndpoint = { - case "consumers" :: consumerId :: "scopes" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - consumer <- NewStyle.function.getConsumerByConsumerId( - consumerId, - callContext - ) - postedData <- Future { - tryo { json.extract[CreateScopeJson] } - } map { - val msg = - s"$InvalidJsonFormat The Json body should be the $CreateScopeJson " - x => unboxFullOrFail(x, callContext, msg) - } - role <- Future { tryo { valueOf(postedData.role_name) } } map { - val msg = - IncorrectRoleName + postedData.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted - .mkString(", ") - x => unboxFullOrFail(x, callContext, msg) - } - _ <- Helper.booleanToFuture( - failMsg = - if (ApiRole.valueOf(postedData.role_name).requiresBankId) - EntitlementIsBankRole - else EntitlementIsSystemRole, - cc = callContext - ) { - ApiRole - .valueOf(postedData.role_name) - .requiresBankId == postedData.bank_id.nonEmpty - } - allowedEntitlements = - canCreateScopeAtOneBank :: canCreateScopeAtAnyBank :: Nil - allowedEntitlementsTxt = - s"$UserHasMissingRoles ${allowedEntitlements.mkString(", ")}!" - _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = - allowedEntitlementsTxt - )(postedData.bank_id, u.userId, allowedEntitlements, callContext) - _ <- Helper.booleanToFuture( - failMsg = BankNotFound, - cc = callContext - ) { - postedData.bank_id.nonEmpty == false || BankX( - BankId(postedData.bank_id), - callContext - ).map(_._1).isEmpty == false - } - _ <- Helper.booleanToFuture( - failMsg = EntitlementAlreadyExists, - cc = callContext - ) { - hasScope(postedData.bank_id, consumerId, role) == false - } - addedEntitlement <- Future { - Scope.scope.vend.addScope( - postedData.bank_id, - consumer.id.get.toString, - postedData.role_name - ) - } map { unboxFull(_) } - } yield { - ( - JSONFactory300.createScopeJson(addedEntitlement), - HttpCode.`201`(callContext) - ) - } - } - } - - val customerAttributeGeneralInfo = - s""" - |CustomerAttributes are used to enhance the OBP Customer object with Bank specific entities. - | - """.stripMargin - - staticResourceDocs += ResourceDoc( - deleteCustomerAttribute, - implementedInApiVersion, - nameOf(deleteCustomerAttribute), - "DELETE", - "/banks/BANK_ID/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID", - "Delete Customer Attribute", - s""" Delete Customer Attribute - | - |$customerAttributeGeneralInfo - | - |Delete a Customer Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some( - List( - canDeleteCustomerAttributeAtOneBank, - canDeleteCustomerAttributeAtAnyBank - ) - ) - ) - - lazy val deleteCustomerAttribute: OBPEndpoint = { - case "banks" :: bankId :: "customers" :: "attributes" :: customerAttributeId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (customerAttribute, callContext) <- NewStyle.function - .deleteCustomerAttribute(customerAttributeId, cc.callContext) - } yield { - (Full(customerAttribute), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createDynamicEndpoint, - implementedInApiVersion, - nameOf(createDynamicEndpoint), - "POST", - "/management/dynamic-endpoints", - "Create Dynamic Endpoint", - s"""Create dynamic endpoints. - | - |Create dynamic endpoints with one json format swagger content. - | - |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields, - |please check `Endpoint Mapping` endpoints. - | - |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n - |when create MethodRouting for given dynamic endpoint, it will be routed to given url. - | - |""", - dynamicEndpointRequestBodyExample, - dynamicEndpointResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEndpointExists, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canCreateDynamicEndpoint)) - ) - - lazy val createDynamicEndpoint: OBPEndpoint = { - case "management" :: "dynamic-endpoints" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - createDynamicEndpointMethod(None, json, cc) - } - } - - staticResourceDocs += ResourceDoc( - createBankLevelDynamicEndpoint, - implementedInApiVersion, - nameOf(createBankLevelDynamicEndpoint), - "POST", - "/management/banks/BANK_ID/dynamic-endpoints", - "Create Bank Level Dynamic Endpoint", - s"""Create dynamic endpoints. - | - |Create dynamic endpoints with one json format swagger content. - | - |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields, - |please check `Endpoint Mapping` endpoints. - | - |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n - |when create MethodRouting for given dynamic endpoint, it will be routed to given url. - | - |""", - dynamicEndpointRequestBodyExample, - dynamicEndpointResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEndpointExists, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canCreateBankLevelDynamicEndpoint, canCreateDynamicEndpoint)) - ) - - lazy val createBankLevelDynamicEndpoint: OBPEndpoint = { - case "management" :: "banks" :: BankId( - bankId - ) :: "dynamic-endpoints" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - createDynamicEndpointMethod(Some(bankId.value), json, cc) - } - } - - staticResourceDocs += ResourceDoc( - updateDynamicEndpointHost, - implementedInApiVersion, - nameOf(updateDynamicEndpointHost), - "PUT", - "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host", - " Update Dynamic Endpoint Host", - s"""Update dynamic endpoint Host. - |The value can be obp_mock, dynamic_entity, or some service url. - |""", - dynamicEndpointHostJson400, - dynamicEndpointHostJson400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEntityNotFoundByDynamicEntityId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canUpdateDynamicEndpoint)) - ) - - lazy val updateDynamicEndpointHost: OBPEndpoint = { - case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateDynamicEndpointHostMethod(None, dynamicEndpointId, json, cc) - } - } - - private def updateDynamicEndpointHostMethod( - bankId: Option[String], - dynamicEndpointId: String, - json: JValue, - cc: CallContext - ) = { - for { - (_, callContext) <- NewStyle.function.getDynamicEndpoint( - bankId, - dynamicEndpointId, - cc.callContext - ) - failMsg = - s"$InvalidJsonFormat The Json body should be the $DynamicEndpointHostJson400" - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[DynamicEndpointHostJson400] - } - (dynamicEndpoint, callContext) <- NewStyle.function - .updateDynamicEndpointHost( - bankId, - dynamicEndpointId, - postedData.host, - cc.callContext - ) - } yield { - (postedData, HttpCode.`201`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - updateBankLevelDynamicEndpointHost, - implementedInApiVersion, - nameOf(updateBankLevelDynamicEndpointHost), - "PUT", - "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host", - " Update Bank Level Dynamic Endpoint Host", - s"""Update Bank Level dynamic endpoint Host. - |The value can be obp_mock, dynamic_entity, or some service url. - |""", - dynamicEndpointHostJson400, - dynamicEndpointHostJson400, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEntityNotFoundByDynamicEntityId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canUpdateBankLevelDynamicEndpoint, canUpdateDynamicEndpoint)) - ) - - lazy val updateBankLevelDynamicEndpointHost: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateDynamicEndpointHostMethod( - Some(bankId), - dynamicEndpointId, - json, - cc - ) - } - } - - staticResourceDocs += ResourceDoc( - getDynamicEndpoint, - implementedInApiVersion, - nameOf(getDynamicEndpoint), - "GET", - "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", - "Get Dynamic Endpoint", - s"""Get a Dynamic Endpoint. - | - | - |Get one DynamicEndpoint, - | - |""", - EmptyBody, - dynamicEndpointResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEndpointNotFoundByDynamicEndpointId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canGetDynamicEndpoint)) - ) - - lazy val getDynamicEndpoint: OBPEndpoint = { - case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getDynamicEndpointMethod(None, dynamicEndpointId, cc) - } - } - - staticResourceDocs += ResourceDoc( - getDynamicEndpoints, - implementedInApiVersion, - nameOf(getDynamicEndpoints), - "GET", - "/management/dynamic-endpoints", - " Get Dynamic Endpoints", - s""" - | - |Get Dynamic Endpoints. - | - |""", - EmptyBody, - ListResult( - "dynamic_endpoints", - List(dynamicEndpointResponseBodyExample) - ), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canGetDynamicEndpoints)) - ) - - lazy val getDynamicEndpoints: OBPEndpoint = { - case "management" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - getDynamicEndpointsMethod(None, cc) - } - } - - private def getDynamicEndpointsMethod( - bankId: Option[String], - cc: CallContext - ) = { - for { - (dynamicEndpoints, _) <- NewStyle.function.getDynamicEndpoints( - bankId, - cc.callContext - ) - } yield { - val resultList = dynamicEndpoints.map[JObject, List[JObject]] { - dynamicEndpoint => - val swaggerJson = parse(dynamicEndpoint.swaggerString) - ( - "user_id", - cc.userId - ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) - } - ( - ListResult("dynamic_endpoints", resultList), - HttpCode.`200`(cc.callContext) - ) - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelDynamicEndpoint, - implementedInApiVersion, - nameOf(getBankLevelDynamicEndpoint), - "GET", - "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", - " Get Bank Level Dynamic Endpoint", - s"""Get a Bank Level Dynamic Endpoint. - |""", - EmptyBody, - dynamicEndpointResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - DynamicEndpointNotFoundByDynamicEndpointId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canGetBankLevelDynamicEndpoint, canGetDynamicEndpoint)) - ) - - lazy val getBankLevelDynamicEndpoint: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc) - } - } - - private def getDynamicEndpointMethod( - bankId: Option[String], - dynamicEndpointId: String, - cc: CallContext - ) = { - for { - (dynamicEndpoint, callContext) <- NewStyle.function.getDynamicEndpoint( - bankId, - dynamicEndpointId, - cc.callContext - ) - } yield { - val swaggerJson = parse(dynamicEndpoint.swaggerString) - val responseJson: JObject = ( - "user_id", - cc.userId - ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) - (responseJson, HttpCode.`200`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelDynamicEndpoints, - implementedInApiVersion, - nameOf(getBankLevelDynamicEndpoints), - "GET", - "/management/banks/BANK_ID/dynamic-endpoints", - "Get Bank Level Dynamic Endpoints", - s""" - | - |Get Bank Level Dynamic Endpoints. - | - |""", - EmptyBody, - ListResult( - "dynamic_endpoints", - List(dynamicEndpointResponseBodyExample) - ), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canGetBankLevelDynamicEndpoints, canGetDynamicEndpoints)) - ) - - lazy val getBankLevelDynamicEndpoints: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getDynamicEndpointsMethod(Some(bankId), cc) - } - } - - private def deleteDynamicEndpointMethod( - bankId: Option[String], - dynamicEndpointId: String, - cc: CallContext - ) = { - for { - deleted <- NewStyle.function.deleteDynamicEndpoint( - bankId, - dynamicEndpointId, - cc.callContext - ) - } yield { - (deleted, HttpCode.`204`(cc.callContext)) - } - } - - staticResourceDocs += ResourceDoc( - deleteDynamicEndpoint, - implementedInApiVersion, - nameOf(deleteDynamicEndpoint), - "DELETE", - "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", - " Delete Dynamic Endpoint", - s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin, - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - DynamicEndpointNotFoundByDynamicEndpointId, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canDeleteDynamicEndpoint)) - ) - - lazy val deleteDynamicEndpoint: OBPEndpoint = { - case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteDynamicEndpointMethod(None, dynamicEndpointId, cc) - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelDynamicEndpoint, - implementedInApiVersion, - nameOf(deleteBankLevelDynamicEndpoint), - "DELETE", - "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", - " Delete Bank Level Dynamic Endpoint", - s"""Delete a Bank Level DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin, - EmptyBody, - EmptyBody, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - DynamicEndpointNotFoundByDynamicEndpointId, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi), - Some(List(canDeleteBankLevelDynamicEndpoint, canDeleteDynamicEndpoint)) - ) - - lazy val deleteBankLevelDynamicEndpoint: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc) - } - } - - staticResourceDocs += ResourceDoc( - getMyDynamicEndpoints, - implementedInApiVersion, - nameOf(getMyDynamicEndpoints), - "GET", - "/my/dynamic-endpoints", - "Get My Dynamic Endpoints", - s"""Get My Dynamic Endpoints.""".stripMargin, - EmptyBody, - ListResult( - "dynamic_endpoints", - List(dynamicEndpointResponseBodyExample) - ), - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi) - ) - - lazy val getMyDynamicEndpoints: OBPEndpoint = { - case "my" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicEndpoints, _) <- NewStyle.function - .getDynamicEndpointsByUserId(cc.userId, cc.callContext) - } yield { - val resultList = dynamicEndpoints.map[JObject, List[JObject]] { - dynamicEndpoint => - val swaggerJson = parse(dynamicEndpoint.swaggerString) - ( - "user_id", - cc.userId - ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) - } - ( - ListResult("dynamic_endpoints", resultList), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyDynamicEndpoint, - implementedInApiVersion, - nameOf(deleteMyDynamicEndpoint), - "DELETE", - "/my/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", - "Delete My Dynamic Endpoint", - s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - DynamicEndpointNotFoundByDynamicEndpointId, - UnknownError - ), - List(apiTagManageDynamicEndpoint, apiTagApi) - ) - - lazy val deleteMyDynamicEndpoint: OBPEndpoint = { - case "my" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicEndpoint, callContext) <- NewStyle.function - .getDynamicEndpoint(None, dynamicEndpointId, cc.callContext) - _ <- Helper.booleanToFuture( - InvalidMyDynamicEndpointUser, - cc = callContext - ) { - dynamicEndpoint.userId.equals(cc.userId) - } - deleted <- NewStyle.function.deleteDynamicEndpoint( - None, - dynamicEndpointId, - callContext - ) - - } yield { - (deleted, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateCustomerAttributeAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateCustomerAttributeAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/customer", - "Create or Update Customer Attribute Definition", - s""" Create or Update Customer Attribute Definition - | - |The category field must be one of: ${AttributeCategory.Customer} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - templateAttributeDefinitionJsonV400, - templateAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some(List(canCreateCustomerAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateCustomerAttributeAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "customer" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Customer}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateAccountAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateAccountAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/account", - "Create or Update Account Attribute Definition", - s""" Create or Update Account Attribute Definition - | - |The category field must be ${AttributeCategory.Account} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - accountAttributeDefinitionJsonV400, - accountAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), - Some(List(canCreateAccountAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateAccountAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "account" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Account}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateProductAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateProductAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/product", - "Create or Update Product Attribute Definition", - s""" Create or Update Product Attribute Definition - | - |The category field must be ${AttributeCategory.Product} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - productAttributeDefinitionJsonV400, - productAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canCreateProductAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateProductAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "product" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Product}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - val productAttributeGeneralInfo = - s""" - |Product Attributes are used to describe a financial Product with a list of typed key value pairs. - | - |Each Product Attribute is linked to its Product by PRODUCT_CODE - | - | - """.stripMargin - - staticResourceDocs += ResourceDoc( - createProductAttribute, - implementedInApiVersion, - nameOf(createProductAttribute), - "POST", - "/banks/BANK_ID/products/PRODUCT_CODE/attribute", - "Create Product Attribute", - s""" Create Product Attribute - | - |$productAttributeGeneralInfo - | - |Typical product attributes might be: - | - |ISIN (for International bonds) - |VKN (for German bonds) - |REDCODE (markit short code for credit derivative) - |LOAN_ID (e.g. used for Anacredit reporting) - | - |ISSUE_DATE (When the bond was issued in the market) - |MATURITY_DATE (End of life time of a product) - |TRADABLE - | - |See [FPML](http://www.fpml.org/) for more examples. - | - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - | - | - |${userAuthenticationMessage(true)} - | - |""", - productAttributeJsonV400, - productAttributeResponseJsonV400, - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canCreateProductAttribute)) - ) - - lazy val createProductAttribute: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "attribute" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId, - u.userId, - canCreateProductAttribute, - callContext - ) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - failMsg = - s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[ProductAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" - productAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - ProductAttributeType.withName(postedData.`type`) - } - (products, callContext) <- NewStyle.function.getProduct( - BankId(bankId), - ProductCode(productCode), - callContext - ) - (productAttribute, callContext) <- NewStyle.function - .createOrUpdateProductAttribute( - BankId(bankId), - ProductCode(productCode), - None, - postedData.name, - productAttributeType, - postedData.value, - postedData.is_active, - callContext: Option[CallContext] - ) - } yield { - ( - createProductAttributeJson(productAttribute), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateProductAttribute, - implementedInApiVersion, - nameOf(updateProductAttribute), - "PUT", - "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", - "Update Product Attribute", - s""" Update Product Attribute. - | - - |$productAttributeGeneralInfo - | - |Update one Product Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - productAttributeJsonV400, - productAttributeResponseJsonV400, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canUpdateProductAttribute)) - ) - - lazy val updateProductAttribute: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId, - u.userId, - canUpdateProductAttribute, - callContext - ) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - failMsg = - s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[ProductAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" - productAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - ProductAttributeType.withName(postedData.`type`) - } - (_, callContext) <- NewStyle.function.getProductAttributeById( - productAttributeId, - callContext - ) - (productAttribute, callContext) <- NewStyle.function - .createOrUpdateProductAttribute( - BankId(bankId), - ProductCode(productCode), - Some(productAttributeId), - postedData.name, - productAttributeType, - postedData.value, - postedData.is_active, - callContext: Option[CallContext] - ) - } yield { - ( - createProductAttributeJson(productAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getProductAttribute, - implementedInApiVersion, - nameOf(getProductAttribute), - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", - "Get Product Attribute", - s""" Get Product Attribute - | - |$productAttributeGeneralInfo - | - |Get one product attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - productAttributeResponseJsonV400, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canUpdateProductAttribute)) - ) - - lazy val getProductAttribute: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId, - u.userId, - canGetProductAttribute, - callContext - ) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - (productAttribute, callContext) <- NewStyle.function - .getProductAttributeById(productAttributeId, callContext) - - } yield { - ( - createProductAttributeJson(productAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createProductFee, - implementedInApiVersion, - nameOf(createProductFee), - "POST", - "/banks/BANK_ID/products/PRODUCT_CODE/fee", - "Create Product Fee", - s"""Create Product Fee - | - |${userAuthenticationMessage(true)} - | - |""", - productFeeJsonV400.copy(product_fee_id = None), - productFeeResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagProduct), - Some(List(canCreateProductFee)) - ) - - lazy val createProductFee: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "fee" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postedData <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ", - 400, - Some(cc) - ) { - json.extract[ProductFeeJsonV400] - } - (_, callContext) <- NewStyle.function.getProduct( - BankId(bankId), - ProductCode(productCode), - Some(cc) - ) - (productFee, callContext) <- NewStyle.function - .createOrUpdateProductFee( - BankId(bankId), - ProductCode(productCode), - None, - postedData.name, - postedData.is_active, - postedData.more_info, - postedData.value.currency, - postedData.value.amount, - postedData.value.frequency, - postedData.value.`type`, - callContext: Option[CallContext] - ) - } yield { - (createProductFeeJson(productFee), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateProductFee, - implementedInApiVersion, - nameOf(updateProductFee), - "PUT", - "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", - "Update Product Fee", - s""" Update Product Fee. - | - |Update one Product Fee by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - productFeeJsonV400.copy(product_fee_id = None), - productFeeResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct), - Some(List(canUpdateProductFee)) - ) - - lazy val updateProductFee: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postedData <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ", - 400, - Some(cc) - ) { - json.extract[ProductFeeJsonV400] - } - (_, callContext) <- NewStyle.function.getProduct( - BankId(bankId), - ProductCode(productCode), - Some(cc) - ) - (_, callContext) <- NewStyle.function.getProductFeeById( - productFeeId, - callContext - ) - (productFee, callContext) <- NewStyle.function - .createOrUpdateProductFee( - BankId(bankId), - ProductCode(productCode), - Some(productFeeId), - postedData.name, - postedData.is_active, - postedData.more_info, - postedData.value.currency, - postedData.value.amount, - postedData.value.frequency, - postedData.value.`type`, - callContext: Option[CallContext] - ) - } yield { - (createProductFeeJson(productFee), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getProductFee, - implementedInApiVersion, - nameOf(getProductFee), - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", - "Get Product Fee", - s""" Get Product Fee - | - |Get one product fee by its id. - | - |${userAuthenticationMessage(false)} - | - |""", - EmptyBody, - productFeeResponseJsonV400, - List( - $BankNotFound, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProductFee: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (productFee, callContext) <- NewStyle.function.getProductFeeById( - productFeeId, - Some(cc) - ) - } yield { - (createProductFeeJson(productFee), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getProductFees, - implementedInApiVersion, - nameOf(getProductFees), - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE/fees", - "Get Product Fees", - s"""Get Product Fees - | - |${userAuthenticationMessage(false)} - | - |""", - EmptyBody, - productFeesResponseJsonV400, - List( - $BankNotFound, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProductFees: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "fees" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (productFees, callContext) <- NewStyle.function - .getProductFeesFromProvider( - BankId(bankId), - ProductCode(productCode), - Some(cc) - ) - } yield { - (createProductFeesJson(productFees), HttpCode.`200`(callContext)) - } - } - } - staticResourceDocs += ResourceDoc( - deleteProductFee, - implementedInApiVersion, - nameOf(deleteProductFee), - "DELETE", - "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", - "Delete Product Fee", - s"""Delete Product Fee - | - |Delete one product fee by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct), - Some(List(canDeleteProductFee)) - ) - - lazy val deleteProductFee: OBPEndpoint = { - case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getProductFeeById( - productFeeId, - Some(cc) - ) - (productFee, callContext) <- NewStyle.function.deleteProductFee( - productFeeId, - Some(cc) - ) - } yield { - (productFee, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateBankAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateBankAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/bank", - "Create or Update Bank Attribute Definition", - s""" Create or Update Bank Attribute Definition - | - |The category field must be ${AttributeCategory.Bank} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - bankAttributeDefinitionJsonV400, - bankAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute), - Some(List(canCreateBankAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateBankAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "bank" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Bank}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createBankAttribute, - implementedInApiVersion, - nameOf(createBankAttribute), - "POST", - "/banks/BANK_ID/attribute", - "Create Bank Attribute", - s""" Create Bank Attribute - | - |Typical product attributes might be: - | - |ISIN (for International bonds) - |VKN (for German bonds) - |REDCODE (markit short code for credit derivative) - |LOAN_ID (e.g. used for Anacredit reporting) - | - |ISSUE_DATE (When the bond was issued in the market) - |MATURITY_DATE (End of life time of a product) - |TRADABLE - | - |See [FPML](http://www.fpml.org/) for more examples. - | - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - | - | - |${userAuthenticationMessage(true)} - | - |""", - bankAttributeJsonV400, - bankAttributeResponseJsonV400, - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute), - Some(List(canCreateBankAttribute)) - ) - - lazy val createBankAttribute: OBPEndpoint = { - case "banks" :: bankId :: "attribute" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - failMsg = - s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[BankAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)" - bankAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - BankAttributeType.withName(postedData.`type`) - } - (bankAttribute, callContext) <- NewStyle.function - .createOrUpdateBankAttribute( - BankId(bankId), - None, - postedData.name, - bankAttributeType, - postedData.value, - postedData.is_active, - callContext: Option[CallContext] - ) - } yield { - (createBankAttributeJson(bankAttribute), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankAttributes, - implementedInApiVersion, - nameOf(getBankAttributes), - "GET", - "/banks/BANK_ID/attributes", - "Get Bank Attributes", - s""" Get Bank Attributes - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - bankAttributesResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute), - Some(List(canGetBankAttribute)) - ) - - lazy val getBankAttributes: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "attributes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributes, callContext) <- NewStyle.function - .getBankAttributesByBank(bankId, cc.callContext) - } yield { - (createBankAttributesJson(attributes), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankAttribute, - implementedInApiVersion, - nameOf(getBankAttribute), - "GET", - "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", - "Get Bank Attribute By BANK_ATTRIBUTE_ID", - s""" Get Bank Attribute By BANK_ATTRIBUTE_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - bankAttributeResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute), - Some(List(canGetBankAttribute)) - ) - - lazy val getBankAttribute: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attributes" :: bankAttributeId :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attribute, callContext) <- NewStyle.function.getBankAttributeById( - bankAttributeId, - cc.callContext - ) - } yield { - (createBankAttributeJson(attribute), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateBankAttribute, - implementedInApiVersion, - nameOf(updateBankAttribute), - "PUT", - "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", - "Update Bank Attribute", - s""" Update Bank Attribute. - | - |Update one Bak Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - bankAttributeJsonV400, - bankAttributeDefinitionJsonV400, - List( - UserHasMissingRoles, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute) - ) - - lazy val updateBankAttribute: OBPEndpoint = { - case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId, - u.userId, - canUpdateBankAttribute, - callContext - ) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - failMsg = - s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 " - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[BankAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)" - productAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - BankAttributeType.withName(postedData.`type`) - } - (_, callContext) <- NewStyle.function.getBankAttributeById( - bankAttributeId, - callContext - ) - (bankAttribute, callContext) <- NewStyle.function - .createOrUpdateBankAttribute( - BankId(bankId), - Some(bankAttributeId), - postedData.name, - productAttributeType, - postedData.value, - postedData.is_active, - callContext: Option[CallContext] - ) - } yield { - ( - createBankAttributeJson(bankAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteBankAttribute, - implementedInApiVersion, - nameOf(deleteBankAttribute), - "DELETE", - "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", - "Delete Bank Attribute", - s""" Delete Bank Attribute - | - |Delete a Bank Attribute by its id. - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - UserHasMissingRoles, - BankNotFound, - UnknownError - ), - List(apiTagBank, apiTagBankAttribute, apiTagAttribute) - ) - - lazy val deleteBankAttribute: OBPEndpoint = { - case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - _ <- NewStyle.function.hasEntitlement( - bankId, - u.userId, - canDeleteBankAttribute, - callContext - ) - (_, callContext) <- NewStyle.function.getBank( - BankId(bankId), - callContext - ) - (bankAttribute, callContext) <- NewStyle.function - .deleteBankAttribute(bankAttributeId, callContext) - } yield { - (Full(bankAttribute), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateTransactionAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateTransactionAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/transaction", - "Create or Update Transaction Attribute Definition", - s""" Create or Update Transaction Attribute Definition - | - |The category field must be ${AttributeCategory.Transaction} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - transactionAttributeDefinitionJsonV400, - transactionAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canCreateTransactionAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateTransactionAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "transaction" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Transaction}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createOrUpdateCardAttributeDefinition, - implementedInApiVersion, - nameOf(createOrUpdateCardAttributeDefinition), - "PUT", - "/banks/BANK_ID/attribute-definitions/card", - "Create or Update Card Attribute Definition", - s""" Create or Update Card Attribute Definition - | - |The category field must be ${AttributeCategory.Card} - | - |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} - | - |${userAuthenticationMessage(true)} - | - |""", - cardAttributeDefinitionJsonV400, - cardAttributeDefinitionResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - UnknownError - ), - List(apiTagCard, apiTagCardAttribute, apiTagAttribute), - Some(List(canCreateCardAttributeDefinitionAtOneBank)) - ) - - lazy val createOrUpdateCardAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "card" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " - for { - postedData <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - json.extract[AttributeDefinitionJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" - attributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - AttributeType.withName(postedData.`type`) - } - failMsg = - s"$InvalidJsonFormat The `Category` field can only accept the following field: " + - s"${AttributeCategory.Card}" - category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - AttributeCategory.withName(postedData.category) - } - (attributeDefinition, callContext) <- - createOrUpdateAttributeDefinition( - bankId, - postedData.name, - category, - attributeType, - postedData.description, - postedData.alias, - postedData.can_be_seen_on_views, - postedData.is_active, - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionJson(attributeDefinition), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteTransactionAttributeDefinition, - implementedInApiVersion, - nameOf(deleteTransactionAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction", - "Delete Transaction Attribute Definition", - s""" Delete Transaction Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canDeleteTransactionAttributeDefinitionAtOneBank)) - ) - - lazy val deleteTransactionAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName( - AttributeCategory.Transaction.toString - ), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteCustomerAttributeDefinition, - implementedInApiVersion, - nameOf(deleteCustomerAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/customer", - "Delete Customer Attribute Definition", - s""" Delete Customer Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some(List(canDeleteCustomerAttributeDefinitionAtOneBank)) - ) - - lazy val deleteCustomerAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "customer" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName(AttributeCategory.Customer.toString), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteAccountAttributeDefinition, - implementedInApiVersion, - nameOf(deleteAccountAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/account", - "Delete Account Attribute Definition", - s""" Delete Account Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), - Some(List(canDeleteAccountAttributeDefinitionAtOneBank)) - ) - - lazy val deleteAccountAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "account" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName(AttributeCategory.Account.toString), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteProductAttributeDefinition, - implementedInApiVersion, - nameOf(deleteProductAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/product", - "Delete Product Attribute Definition", - s""" Delete Product Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canDeleteProductAttributeDefinitionAtOneBank)) - ) - - lazy val deleteProductAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "product" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName(AttributeCategory.Product.toString), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteCardAttributeDefinition, - implementedInApiVersion, - nameOf(deleteCardAttributeDefinition), - "DELETE", - "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/card", - "Delete Card Attribute Definition", - s""" Delete Card Attribute Definition by ATTRIBUTE_DEFINITION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCard, apiTagCardAttribute, apiTagAttribute), - Some(List(canDeleteCardAttributeDefinitionAtOneBank)) - ) - - lazy val deleteCardAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: attributeDefinitionId :: "card" :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- deleteAttributeDefinition( - attributeDefinitionId, - AttributeCategory.withName(AttributeCategory.Card.toString), - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getProductAttributeDefinition, - implementedInApiVersion, - nameOf(getProductAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/product", - "Get Product Attribute Definition", - s""" Get Product Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - productAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), - Some(List(canGetProductAttributeDefinitionAtOneBank)) - ) - - lazy val getProductAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "product" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName(AttributeCategory.Product.toString), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomerAttributeDefinition, - implementedInApiVersion, - nameOf(getCustomerAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/customer", - "Get Customer Attribute Definition", - s""" Get Customer Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), - Some(List(canGetCustomerAttributeDefinitionAtOneBank)) - ) - - lazy val getCustomerAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "customer" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName(AttributeCategory.Customer.toString), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getAccountAttributeDefinition, - implementedInApiVersion, - nameOf(getAccountAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/account", - "Get Account Attribute Definition", - s""" Get Account Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - accountAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), - Some(List(canGetAccountAttributeDefinitionAtOneBank)) - ) - - lazy val getAccountAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "account" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName(AttributeCategory.Account.toString), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getTransactionAttributeDefinition, - implementedInApiVersion, - nameOf(getTransactionAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/transaction", - "Get Transaction Attribute Definition", - s""" Get Transaction Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - transactionAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), - Some(List(canGetTransactionAttributeDefinitionAtOneBank)) - ) - - lazy val getTransactionAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "transaction" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName( - AttributeCategory.Transaction.toString - ), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson( - attributeDefinitions - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCardAttributeDefinition, - implementedInApiVersion, - nameOf(getCardAttributeDefinition), - "GET", - "/banks/BANK_ID/attribute-definitions/card", - "Get Card Attribute Definition", - s""" Get Card Attribute Definition - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - cardAttributeDefinitionsResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCard, apiTagCardAttribute, apiTagAttribute), - Some(List(canGetCardAttributeDefinitionAtOneBank)) - ) - - lazy val getCardAttributeDefinition: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "attribute-definitions" :: "card" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributeDefinitions, callContext) <- getAttributeDefinition( - AttributeCategory.withName(AttributeCategory.Card.toString), - cc.callContext - ) - } yield { - ( - JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteUserCustomerLink, - implementedInApiVersion, - nameOf(deleteUserCustomerLink), - "DELETE", - "/banks/BANK_ID/user_customer_links/USER_CUSTOMER_LINK_ID", - "Delete User Customer Link", - s""" Delete User Customer Link by USER_CUSTOMER_LINK_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer), - Some(List(canDeleteUserCustomerLink)) - ) - - lazy val deleteUserCustomerLink: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user_customer_links" :: userCustomerLinkId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (deleted, callContext) <- UserCustomerLinkNewStyle - .deleteUserCustomerLink( - userCustomerLinkId, - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserCustomerLinksByUserId, - implementedInApiVersion, - nameOf(getUserCustomerLinksByUserId), - "GET", - "/banks/BANK_ID/user_customer_links/users/USER_ID", - "Get User Customer Links by User", - s""" Get User Customer Links by USER_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - userCustomerLinksJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer), - Some(List(canGetUserCustomerLink)) - ) - - lazy val getUserCustomerLinksByUserId: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user_customer_links" :: "users" :: userId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle - .getUserCustomerLinksByUserId( - userId, - cc.callContext - ) - } yield { - ( - JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createUserCustomerLinks, - implementedInApiVersion, - "createUserCustomerLinks", - "POST", - "/banks/BANK_ID/user_customer_links", - "Create User Customer Link", - s"""Link a User to a Customer - | - |${userAuthenticationMessage(true)} - | - |""", - createUserCustomerLinkJson, - userCustomerLinkJson, - List( - $AuthenticatedUserIsRequired, - InvalidBankIdFormat, - $BankNotFound, - InvalidJsonFormat, - CustomerNotFoundByCustomerId, - UserHasMissingRoles, - CustomerAlreadyExistsForUser, - CreateUserCustomerLinksError, - UnknownError - ), - List(apiTagCustomer, apiTagUser), - Some(List(canCreateUserCustomerLinkAtAnyBank, canCreateUserCustomerLink)) - ) - - lazy val createUserCustomerLinks: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user_customer_links" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- NewStyle.function.tryons( - s"$InvalidBankIdFormat", - 400, - cc.callContext - ) { - assert(isValidID(bankId.value)) - } - postedData <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $CreateUserCustomerLinkJson ", - 400, - cc.callContext - ) { - json.extract[CreateUserCustomerLinkJson] - } - user <- Users.users.vend.getUserByUserIdFuture( - postedData.user_id - ) map { x => - unboxFullOrFail(x, cc.callContext, UserNotFoundByUserId, 404) - } - _ <- booleanToFuture( - "Field customer_id is not defined in the posted json!", - 400, - cc.callContext - ) { - postedData.customer_id.nonEmpty - } - (customer, callContext) <- NewStyle.function.getCustomerByCustomerId( - postedData.customer_id, - cc.callContext - ) - _ <- booleanToFuture( - s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to matches BANK_ID(${bankId.value}) in URL", - 400, - callContext - ) { - customer.bankId == bankId.value - } - _ <- booleanToFuture(CustomerAlreadyExistsForUser, 400, callContext) { - UserCustomerLink.userCustomerLink.vend - .getUserCustomerLink(postedData.user_id, postedData.customer_id) - .isEmpty == true - } - userCustomerLink <- Future { - UserCustomerLink.userCustomerLink.vend.createUserCustomerLink( - postedData.user_id, - postedData.customer_id, - new Date(), - true - ) - } map { x => - unboxFullOrFail(x, callContext, CreateUserCustomerLinksError, 400) - } - } yield { - ( - code.api.v2_0_0.JSONFactory200 - .createUserCustomerLinkJSON(userCustomerLink), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserCustomerLinksByCustomerId, - implementedInApiVersion, - nameOf(getUserCustomerLinksByCustomerId), - "GET", - "/banks/BANK_ID/user_customer_links/customers/CUSTOMER_ID", - "Get User Customer Links by Customer", - s""" Get User Customer Links by CUSTOMER_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - userCustomerLinksJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer), - Some(List(canGetUserCustomerLink)) - ) - - lazy val getUserCustomerLinksByCustomerId: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "user_customer_links" :: "customers" :: customerId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (userCustomerLinks, callContext) <- getUserCustomerLinks( - customerId, - cc.callContext - ) - } yield { - ( - JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCorrelatedUsersInfoByCustomerId, - implementedInApiVersion, - nameOf(getCorrelatedUsersInfoByCustomerId), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/correlated-users", - "Get Correlated User Info by Customer", - s"""Get Correlated User Info by CUSTOMER_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - customerAndUsersWithAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer), - Some(List(canGetCorrelatedUsersInfoAtAnyBank, canGetCorrelatedUsersInfo)) - ) - - lazy val getCorrelatedUsersInfoByCustomerId: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "customers" :: customerId :: "correlated-users" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, cc.callContext) - (userCustomerLinks, callContext) <- getUserCustomerLinks( - customerId, - callContext - ) - (users, callContext) <- NewStyle.function.getUsersByUserIds( - userCustomerLinks.map(_.userId), - callContext - ) - (attributes, callContext) <- NewStyle.function - .getUserAttributesByUsers( - userCustomerLinks.map(_.userId), - callContext - ) - } yield { - ( - JSONFactory400.createCustomerAdUsersWithAttributesJson( - customer, - users, - attributes - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyCorrelatedEntities, - implementedInApiVersion, - nameOf(getMyCorrelatedEntities), - "GET", - "/my/correlated-entities", - "Get Correlated Entities for the current User", - s"""Correlated Entities are users and customers linked to the currently authenticated user via User-Customer-Links - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - correlatedUsersResponseJson, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagCustomer) - ) - - private def getCorrelatedUsersInfo( - userCustomerLink: UserCustomerLink, - callContext: Option[CallContext] - ) = for { - (customer, callContext) <- NewStyle.function.getCustomerByCustomerId( - userCustomerLink.customerId, - callContext - ) - (userCustomerLinks, callContext) <- getUserCustomerLinks( - userCustomerLink.customerId, - callContext - ) - (users, callContext) <- NewStyle.function.getUsersByUserIds( - userCustomerLinks.map(_.userId), - callContext - ) - (attributes, callContext) <- NewStyle.function.getUserAttributesByUsers( - userCustomerLinks.map(_.userId), - callContext - ) - } yield { - (customer, users, attributes, callContext) - } - - lazy val getMyCorrelatedEntities: OBPEndpoint = { - case "my" :: "correlated-entities" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle - .getUserCustomerLinksByUserId( - u.userId, - callContext - ) - correlatedUserInfoList <- Future.sequence( - userCustomerLinks.map(getCorrelatedUsersInfo(_, callContext)) - ) - } yield { - ( - CorrelatedEntities( - correlatedUserInfoList.map(correlatedUserInfo => - JSONFactory400.createCustomerAdUsersWithAttributesJson( - correlatedUserInfo._1, - correlatedUserInfo._2, - correlatedUserInfo._3 - ) - ) - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createCustomer, - implementedInApiVersion, - nameOf(createCustomer), - "POST", - "/banks/BANK_ID/customers", - "Create Customer", - s""" - |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc. - |Dates need to be in the format 2013-01-21T23:08:00Z - | - |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call. - | - |${userAuthenticationMessage(true)} - |""", - postCustomerJsonV310, - customerJsonV310, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - CustomerNumberAlreadyExists, - UserNotFoundById, - CustomerAlreadyExistsForUser, - CreateConsumerError, - UnknownError - ), - List(apiTagCustomer, apiTagPerson), - Some(List(canCreateCustomer, canCreateCustomerAtAnyBank)) - ) - lazy val createCustomer: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "customers" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postedData <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 ", - 400, - cc.callContext - ) { - json.extract[PostCustomerJsonV310] - } - _ <- Helper.booleanToFuture( - failMsg = - InvalidJsonContent + s" The field dependants(${postedData.dependants}) not equal the length(${postedData.dob_of_dependants.length}) of dob_of_dependants array", - 400, - cc.callContext - ) { - postedData.dependants == postedData.dob_of_dependants.length - } - (customer, callContext) <- NewStyle.function.createCustomer( - bankId, - postedData.legal_name, - postedData.mobile_phone_number, - postedData.email, - CustomerFaceImage( - postedData.face_image.date, - postedData.face_image.url - ), - postedData.date_of_birth, - postedData.relationship_status, - postedData.dependants, - postedData.dob_of_dependants, - postedData.highest_education_attained, - postedData.employment_status, - postedData.kyc_status, - postedData.last_ok_date, - Option( - CreditRating( - postedData.credit_rating.rating, - postedData.credit_rating.source - ) - ), - Option( - CreditLimit( - postedData.credit_limit.currency, - postedData.credit_limit.amount - ) - ), - postedData.title, - postedData.branch_id, - postedData.name_suffix, - cc.callContext - ) - } yield { - ( - JSONFactory310.createCustomerJson(customer), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getAccountsMinimalByCustomerId, - implementedInApiVersion, - nameOf(getAccountsMinimalByCustomerId), - "GET", - "/customers/CUSTOMER_ID/accounts-minimal", - "Get Accounts Minimal for a Customer", - s"""Get Accounts Minimal by CUSTOMER_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - accountsMinimalJson400, - List( - $AuthenticatedUserIsRequired, - CustomerNotFound, - UnknownError - ), - List(apiTagAccount), - Some(List(canGetAccountsMinimalForCustomerAtOneBank, canGetAccountsMinimalForCustomerAtAnyBank)) - ) - - lazy val getAccountsMinimalByCustomerId: OBPEndpoint = { - case "customers" :: customerId :: "accounts-minimal" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - (customer, callContext) <- getCustomerByCustomerId( - customerId, - callContext - ) - _ <- NewStyle.function.hasAtLeastOneEntitlement(customer.bankId, u.userId, canGetAccountsMinimalForCustomerAtOneBank :: canGetAccountsMinimalForCustomerAtAnyBank :: Nil, callContext) - (userCustomerLinks, callContext) <- getUserCustomerLinks( - customerId, - callContext - ) - (users, callContext) <- getUsersByUserIds( - userCustomerLinks.map(_.userId), - callContext - ) - } yield { - val accountAccess = - for (user <- users) - yield Views.views.vend.privateViewsUserCanAccess(user)._2 - ( - JSONFactory400.createAccountsMinimalJson400( - accountAccess.flatten - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteTransactionCascade, - implementedInApiVersion, - nameOf(deleteTransactionCascade), - "DELETE", - "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID", - "Delete Transaction Cascade", - s"""Delete a Transaction Cascade specified by TRANSACTION_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagTransaction), - Some(List(canDeleteTransactionCascade)) - ) - - lazy val deleteTransactionCascade: OBPEndpoint = { - case "management" :: "cascading" :: "banks" :: BankId( - bankId - ) :: "accounts" :: AccountId(accountId) :: - "transactions" :: TransactionId( - transactionId - ) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getTransaction( - bankId, - accountId, - transactionId, - cc.callContext - ) - _ <- Future( - DeleteTransactionCascade.atomicDelete( - bankId, - accountId, - transactionId - ) - ) - } yield { - (Full(true), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteAccountCascade, - implementedInApiVersion, - nameOf(deleteAccountCascade), - "DELETE", - "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID", - "Delete Account Cascade", - s"""Delete an Account Cascade specified by ACCOUNT_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagAccount), - Some(List(canDeleteAccountCascade)) - ) - - lazy val deleteAccountCascade: OBPEndpoint = { - case "management" :: "cascading" :: "banks" :: BankId( - bankId - ) :: "accounts" :: AccountId(accountId) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - result <- Future(DeleteAccountCascade.atomicDelete(bankId, accountId)) - } yield { - if (result.getOrElse(false)) - (Full(true), HttpCode.`200`(cc)) - else - (Full(false), HttpCode.`404`(cc)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteBankCascade, - implementedInApiVersion, - nameOf(deleteBankCascade), - "DELETE", - "/management/cascading/banks/BANK_ID", - "Delete Bank Cascade", - s"""Delete a Bank Cascade specified by BANK_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagBank), - Some(List(canDeleteBankCascade)) - ) - - lazy val deleteBankCascade: OBPEndpoint = { - case "management" :: "cascading" :: "banks" :: BankId( - bankId - ) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - _ <- Future(DeleteBankCascade.atomicDelete(bankId)) - } yield { - (Full(true), HttpCode.`200`(cc)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteProductCascade, - implementedInApiVersion, - nameOf(deleteProductCascade), - "DELETE", - "/management/cascading/banks/BANK_ID/products/PRODUCT_CODE", - "Delete Product Cascade", - s"""Delete a Product Cascade specified by PRODUCT_CODE. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct), - Some(List(canDeleteProductCascade)) - ) - - lazy val deleteProductCascade: OBPEndpoint = { - case "management" :: "cascading" :: "banks" :: BankId( - bankId - ) :: "products" :: ProductCode(code) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getProduct( - bankId, - code, - Some(cc) - ) - _ <- Future(DeleteProductCascade.atomicDelete(bankId, code)) - } yield { - (Full(true), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteCustomerCascade, - implementedInApiVersion, - nameOf(deleteCustomerCascade), - "DELETE", - "/management/cascading/banks/BANK_ID/customers/CUSTOMER_ID", - "Delete Customer Cascade", - s"""Delete a Customer Cascade specified by CUSTOMER_ID. - | - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - CustomerNotFoundByCustomerId, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCustomer), - Some(List(canDeleteCustomerCascade)) - ) - - lazy val deleteCustomerCascade: OBPEndpoint = { - case "management" :: "cascading" :: "banks" :: BankId( - bankId - ) :: "customers" :: CustomerId(customerId) :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getCustomerByCustomerId( - customerId.value, - Some(cc) - ) - _ <- Future(DeleteCustomerCascade.atomicDelete(customerId)) - } yield { - (Full(true), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createExplicitCounterparty, - implementedInApiVersion, - "createCounterparty", - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", - "Create Counterparty (Explicit)", - s"""This endpoint creates an (Explicit) Counterparty for an Account. - | - |For an introduction to Counterparties in OBP see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - postCounterpartyJson400, - counterpartyWithMetadataJson400, - List( - $AuthenticatedUserIsRequired, - InvalidAccountIdFormat, - InvalidBankIdFormat, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - InvalidJsonFormat, - InvalidISOCurrencyCode, - ViewNotFound, - CounterpartyAlreadyExists, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount) - ) - - lazy val createExplicitCounterparty: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - InvalidAccountIdFormat, - cc = callContext - ) { isValidID(accountId.value) } - _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { - isValidID(bankId.value) - } - postJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostCounterpartyJSON", - 400, - callContext - ) { - json.extract[PostCounterpartyJson400] - } - - _ <- Helper.booleanToFuture( - s"$NoViewPermission can_add_counterparty. Please use a view with that permission or add the permission to this view.", - 403, - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_ADD_COUNTERPARTY) - } - - (counterparty, callContext) <- Connector.connector.vend - .checkCounterpartyExists( - postJson.name, - bankId.value, - accountId.value, - viewId.value, - callContext - ) - - _ <- Helper.booleanToFuture( - CounterpartyAlreadyExists.replace( - "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.", - s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" - ), - cc = callContext - ) { - counterparty.isEmpty - } - _ <- booleanToFuture( - s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}", - cc = callContext - ) { - postJson.description.length <= 36 - } - _ <- Helper.booleanToFuture( - s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'", - cc = callContext - ) { - APIUtil.isValidCurrencyISOCode(postJson.currency) - } - - // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account. - (_, callContext) <- - if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "OBP" - ) && postJson.other_account_routing_scheme.equalsIgnoreCase( - "OBP" - ) - ) { - for { - (_, callContext) <- NewStyle.function.getBank( - BankId(postJson.other_bank_routing_address), - Some(cc) - ) - (account, callContext) <- NewStyle.function - .checkBankAccountExists( - BankId(postJson.other_bank_routing_address), - AccountId(postJson.other_account_routing_address), - callContext - ) - - } yield { - (account, callContext) - } - } else if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "OBP" - ) && postJson.other_account_secondary_routing_scheme - .equalsIgnoreCase("OBP") - ) { - for { - (_, callContext) <- NewStyle.function.getBank( - BankId(postJson.other_bank_routing_address), - Some(cc) - ) - (account, callContext) <- NewStyle.function - .checkBankAccountExists( - BankId(postJson.other_bank_routing_address), - AccountId( - postJson.other_account_secondary_routing_address - ), - callContext - ) - - } yield { - (account, callContext) - } - } else if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "ACCOUNT_NUMBER" - ) || postJson.other_bank_routing_scheme.equalsIgnoreCase( - "ACCOUNT_NO" - ) - ) { - for { - bankIdOption <- Future.successful( - if (postJson.other_bank_routing_address.isEmpty) None - else Some(postJson.other_bank_routing_address) - ) - (account, callContext) <- NewStyle.function - .getBankAccountByNumber( - bankIdOption.map(BankId(_)), - postJson.other_bank_routing_address, - callContext - ) - } yield { - (account, callContext) - } - } else - Future { (Full(()), Some(cc)) } - - otherAccountRoutingSchemeOBPFormat = - if ( - postJson.other_account_routing_scheme.equalsIgnoreCase( - "AccountNo" - ) - ) "ACCOUNT_NUMBER" - else - StringHelpers - .snakify(postJson.other_account_routing_scheme) - .toUpperCase - - (counterparty, callContext) <- NewStyle.function.createCounterparty( - name = postJson.name, - description = postJson.description, - currency = postJson.currency, - createdByUserId = u.userId, - thisBankId = bankId.value, - thisAccountId = accountId.value, - thisViewId = viewId.value, - otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat, - otherAccountRoutingAddress = - postJson.other_account_routing_address, - otherAccountSecondaryRoutingScheme = StringHelpers - .snakify(postJson.other_account_secondary_routing_scheme) - .toUpperCase, - otherAccountSecondaryRoutingAddress = - postJson.other_account_secondary_routing_address, - otherBankRoutingScheme = StringHelpers - .snakify(postJson.other_bank_routing_scheme) - .toUpperCase, - otherBankRoutingAddress = postJson.other_bank_routing_address, - otherBranchRoutingScheme = StringHelpers - .snakify(postJson.other_branch_routing_scheme) - .toUpperCase, - otherBranchRoutingAddress = postJson.other_branch_routing_address, - isBeneficiary = postJson.is_beneficiary, - bespoke = postJson.bespoke.map(bespoke => - CounterpartyBespoke(bespoke.key, bespoke.value) - ), - callContext - ) - - (counterpartyMetadata, callContext) <- NewStyle.function - .getOrCreateMetadata( - bankId, - accountId, - counterparty.counterpartyId, - postJson.name, - callContext - ) - - } yield { - ( - JSONFactory400.createCounterpartyWithMetadataJson400( - counterparty, - counterpartyMetadata - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteExplicitCounterparty, - implementedInApiVersion, - nameOf(deleteExplicitCounterparty), - "POST", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", - "Delete Counterparty (Explicit)", - s"""This endpoint deletes the Counterparty on the Account / View specified by the COUNTERPARTY_ID. - |It also deletes any related Counterparty Metadata. - | - |The User calling this endpoint must have access to the View specified in the URL and that View must have the permission `can_delete_counterparty`. - | - |For a general introduction to Counterparties in OBP see ${Glossary - .getGlossaryItemLink("Counterparties")} - | | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - InvalidAccountIdFormat, - InvalidBankIdFormat, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount) - ) - - lazy val deleteExplicitCounterparty: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( - counterpartyId - ) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - InvalidAccountIdFormat, - cc = callContext - ) { isValidID(accountId.value) } - _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { - isValidID(bankId.value) - } - - _ <- Helper.booleanToFuture( - s"$NoViewPermission can_delete_counterparty. Please use a view with that permission or add the permission to this view.", - 403, - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_DELETE_COUNTERPARTY) - } - - (counterparty, callContext) <- NewStyle.function - .deleteCounterpartyByCounterpartyId(counterpartyId, callContext) - - (counterpartyMetadata, callContext) <- NewStyle.function - .deleteMetadata( - bankId, - accountId, - counterpartyId.value, - callContext - ) - - } yield { - (Full(counterparty), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteCounterpartyForAnyAccount, - implementedInApiVersion, - nameOf(deleteCounterpartyForAnyAccount), - "DELETE", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", - "Delete Counterparty for any account (Explicit)", - s"""This is a management endpoint that enables the deletion of any specified Counterparty along with any related Metadata of that Counterparty. - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - $BankAccountNotFound, - $BankNotFound, - InvalidAccountIdFormat, - InvalidBankIdFormat, - UserHasMissingRoles, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount), - Some(List(canDeleteCounterparty, canDeleteCounterpartyAtAnyBank)) - ) - - lazy val deleteCounterpartyForAnyAccount: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( - counterpartyId - ) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), bank, account, callContext) <- SS.userBankAccount - - _ <- Helper.booleanToFuture( - InvalidAccountIdFormat, - cc = callContext - ) { isValidID(accountId.value) } - - _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { - isValidID(bankId.value) - } - - (counterparty, callContext) <- NewStyle.function - .deleteCounterpartyByCounterpartyId(counterpartyId, callContext) - - (counterpartyMetadata, callContext) <- NewStyle.function - .deleteMetadata( - bankId, - accountId, - counterpartyId.value, - callContext - ) - - } yield { - (Full(counterparty), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createCounterpartyForAnyAccount, - implementedInApiVersion, - "createCounterpartyForAnyAccount", - "POST", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", - "Create Counterparty for any account (Explicit)", - s"""This is a management endpoint that allows the creation of a Counterparty on any Account. - | - |For an introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - postCounterpartyJson400, - counterpartyWithMetadataJson400, - List( - $AuthenticatedUserIsRequired, - InvalidAccountIdFormat, - InvalidBankIdFormat, - $BankNotFound, - $BankAccountNotFound, - AccountNotFound, - InvalidJsonFormat, - InvalidISOCurrencyCode, - ViewNotFound, - CounterpartyAlreadyExists, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount), - Some(List(canCreateCounterparty, canCreateCounterpartyAtAnyBank)) - ) - - lazy val createCounterpartyForAnyAccount: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), bank, account, callContext) <- SS.userBankAccount - postJson <- NewStyle.function.tryons( - InvalidJsonFormat, - 400, - callContext - ) { - json.extract[PostCounterpartyJson400] - } - _ <- Helper.booleanToFuture( - s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}", - cc = callContext - ) { postJson.description.length <= 36 } - - (counterparty, callContext) <- Connector.connector.vend - .checkCounterpartyExists( - postJson.name, - bankId.value, - accountId.value, - viewId.value, - callContext - ) - - _ <- Helper.booleanToFuture( - CounterpartyAlreadyExists.replace( - "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.", - s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" - ), - cc = callContext - ) { - counterparty.isEmpty - } - - _ <- Helper.booleanToFuture( - s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'", - cc = callContext - ) { - APIUtil.isValidCurrencyISOCode(postJson.currency) - } - - // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account. - (_, callContext) <- - if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "OBP" - ) && postJson.other_account_routing_scheme.equalsIgnoreCase( - "OBP" - ) - ) { - for { - (_, callContext) <- NewStyle.function.getBank( - BankId(postJson.other_bank_routing_address), - Some(cc) - ) - (account, callContext) <- NewStyle.function - .checkBankAccountExists( - BankId(postJson.other_bank_routing_address), - AccountId(postJson.other_account_routing_address), - callContext - ) - - } yield { - (account, callContext) - } - } else if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "OBP" - ) && postJson.other_account_secondary_routing_scheme - .equalsIgnoreCase("OBP") - ) { - for { - (_, callContext) <- NewStyle.function.getBank( - BankId(postJson.other_bank_routing_address), - Some(cc) - ) - (account, callContext) <- NewStyle.function - .checkBankAccountExists( - BankId(postJson.other_bank_routing_address), - AccountId( - postJson.other_account_secondary_routing_address - ), - callContext - ) - - } yield { - (account, callContext) - } - } else if ( - postJson.other_bank_routing_scheme.equalsIgnoreCase( - "ACCOUNT_NUMBER" - ) || postJson.other_bank_routing_scheme.equalsIgnoreCase( - "ACCOUNT_NO" - ) - ) { - for { - bankIdOption <- Future.successful( - if (postJson.other_bank_routing_address.isEmpty) None - else Some(postJson.other_bank_routing_address) - ) - (account, callContext) <- NewStyle.function - .getBankAccountByNumber( - bankIdOption.map(BankId(_)), - postJson.other_bank_routing_address, - callContext - ) - } yield { - (account, callContext) - } - } else - Future { (Full(()), Some(cc)) } - - otherAccountRoutingSchemeOBPFormat = - if ( - postJson.other_account_routing_scheme.equalsIgnoreCase( - "AccountNo" - ) - ) "ACCOUNT_NUMBER" - else - StringHelpers - .snakify(postJson.other_account_routing_scheme) - .toUpperCase - - (counterparty, callContext) <- NewStyle.function.createCounterparty( - name = postJson.name, - description = postJson.description, - currency = postJson.currency, - createdByUserId = u.userId, - thisBankId = bankId.value, - thisAccountId = accountId.value, - thisViewId = Constant.SYSTEM_OWNER_VIEW_ID, - otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat, - otherAccountRoutingAddress = - postJson.other_account_routing_address, - otherAccountSecondaryRoutingScheme = StringHelpers - .snakify(postJson.other_account_secondary_routing_scheme) - .toUpperCase, - otherAccountSecondaryRoutingAddress = - postJson.other_account_secondary_routing_address, - otherBankRoutingScheme = StringHelpers - .snakify(postJson.other_bank_routing_scheme) - .toUpperCase, - otherBankRoutingAddress = postJson.other_bank_routing_address, - otherBranchRoutingScheme = StringHelpers - .snakify(postJson.other_branch_routing_scheme) - .toUpperCase, - otherBranchRoutingAddress = postJson.other_branch_routing_address, - isBeneficiary = postJson.is_beneficiary, - bespoke = postJson.bespoke.map(bespoke => - CounterpartyBespoke(bespoke.key, bespoke.value) - ), - callContext - ) - - (counterpartyMetadata, callContext) <- NewStyle.function - .getOrCreateMetadata( - bankId, - accountId, - counterparty.counterpartyId, - postJson.name, - callContext - ) - - } yield { - ( - JSONFactory400.createCounterpartyWithMetadataJson400( - counterparty, - counterpartyMetadata - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getExplicitCounterpartiesForAccount, - implementedInApiVersion, - "getExplicitCounterpartiesForAccount", - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", - "Get Counterparties (Explicit)", - s"""Get the Counterparties that have been explicitly created on the specified Account / View. - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - counterpartiesJson400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - ViewNotFound, - UnknownError - ), - List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount) - ) - - lazy val getExplicitCounterpartiesForAccount: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = s"${NoViewPermission}can_get_counterparty", - 403, - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY) - } - (counterparties, callContext) <- NewStyle.function.getCounterparties( - bankId, - accountId, - viewId, - callContext - ) - // Here we need create the metadata for all the explicit counterparties. maybe show them in json response. - // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata. - _ <- Helper.booleanToFuture( - CreateOrUpdateCounterpartyMetadataError, - 400, - cc = callContext - ) { - { - for { - counterparty <- counterparties - } yield { - Counterparties.counterparties.vend.getOrCreateMetadata( - bankId, - accountId, - counterparty.counterpartyId, - counterparty.name - ) match { - case Full(_) => true - case _ => false - } - } - }.forall(_ == true) - } - } yield { - val counterpartiesJson = - JSONFactory400.createCounterpartiesJson400(counterparties) - (counterpartiesJson, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getCounterpartiesForAnyAccount, - implementedInApiVersion, - nameOf(getCounterpartiesForAnyAccount), - "GET", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", - "Get Counterparties for any account (Explicit)", - s"""This is a management endpoint that gets the Counterparties that have been explicitly created for an Account / View. - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - counterpartiesJson400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - UnknownError - ), - List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount), - Some(List(canGetCounterparties, canGetCounterpartiesAtAnyBank)) - ) - - lazy val getCounterpartiesForAnyAccount: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), bank, account, callContext) <- SS.userBankAccount - (counterparties, callContext) <- NewStyle.function.getCounterparties( - bankId, - accountId, - viewId, - callContext - ) - // Here we need create the metadata for all the explicit counterparties. maybe show them in json response. - // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata. - _ <- Helper.booleanToFuture( - CreateOrUpdateCounterpartyMetadataError, - 400, - cc = callContext - ) { - { - for { - counterparty <- counterparties - } yield { - Counterparties.counterparties.vend.getOrCreateMetadata( - bankId, - accountId, - counterparty.counterpartyId, - counterparty.name - ) match { - case Full(_) => true - case _ => false - } - } - }.forall(_ == true) - } - } yield { - val counterpartiesJson = - JSONFactory400.createCounterpartiesJson400(counterparties) - (counterpartiesJson, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getExplicitCounterpartyById, - implementedInApiVersion, - "getExplicitCounterpartyById", - "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", - "Get Counterparty by Id (Explicit)", - s"""This endpoint returns a single Counterparty on an Account View specified by its COUNTERPARTY_ID: - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - counterpartyWithMetadataJson400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - $BankAccountNotFound, - $UserNoPermissionAccessView, - UnknownError - ), - List( - apiTagCounterparty, - apiTagPSD2PIS, - apiTagPsd2, - apiTagCounterpartyMetaData - ) - ) - - lazy val getExplicitCounterpartyById: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( - counterpartyId - ) :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, view, callContext) <- - SS.userBankAccountView - _ <- Helper.booleanToFuture( - failMsg = s"${NoViewPermission}can_get_counterparty", - 403, - cc = callContext - ) { - view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY) - } - (counterparty, callContext) <- NewStyle.function - .getCounterpartyByCounterpartyId(counterpartyId, callContext) - counterpartyMetadata <- NewStyle.function.getMetadata( - bankId, - accountId, - counterpartyId.value, - callContext - ) - } yield { - val counterpartyJson = - JSONFactory400.createCounterpartyWithMetadataJson400( - counterparty, - counterpartyMetadata - ) - (counterpartyJson, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getCounterpartyByNameForAnyAccount, - implementedInApiVersion, - nameOf(getCounterpartyByNameForAnyAccount), - "GET", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparty-names/COUNTERPARTY_NAME", - "Get Counterparty by name for any account (Explicit) ", - s"""This is a management endpoint that allows the retrieval of any Counterparty on an Account / View by its Name. - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - counterpartyWithMetadataJson400, - List( - $AuthenticatedUserIsRequired, - InvalidAccountIdFormat, - InvalidBankIdFormat, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - ViewNotFound, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount), - Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty)) - ) - - lazy val getCounterpartyByNameForAnyAccount: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId( - viewId - ) :: "counterparty-names" :: counterpartyName :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), bank, account, callContext) <- SS.userBankAccount - - (counterparty, callContext) <- Connector.connector.vend - .checkCounterpartyExists( - counterpartyName, - bankId.value, - accountId.value, - viewId.value, - callContext - ) - - counterparty <- NewStyle.function.tryons( - CounterpartyNotFound.replace( - "The BANK_ID / ACCOUNT_ID specified does not exist on this server.", - s"COUNTERPARTY_NAME(${counterpartyName}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" - ), - 400, - callContext - ) { - counterparty.head - } - - (counterpartyMetadata, callContext) <- NewStyle.function - .getOrCreateMetadata( - bankId, - accountId, - counterparty.counterpartyId, - counterparty.name, - callContext - ) - - } yield { - ( - JSONFactory400.createCounterpartyWithMetadataJson400( - counterparty, - counterpartyMetadata - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getCounterpartyByIdForAnyAccount, - implementedInApiVersion, - nameOf(getCounterpartyByIdForAnyAccount), - "GET", - "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", - "Get Counterparty by Id for any account (Explicit)", - s"""This is a management endpoint that gets information about any single explicitly created Counterparty on an Account / View specified by its COUNTERPARTY_ID", - | - |For a general introduction to Counterparties in OBP, see ${Glossary - .getGlossaryItemLink("Counterparties")} - | - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - EmptyBody, - counterpartyWithMetadataJson400, - List( - $AuthenticatedUserIsRequired, - InvalidAccountIdFormat, - InvalidBankIdFormat, - $BankNotFound, - $BankAccountNotFound, - InvalidJsonFormat, - ViewNotFound, - UnknownError - ), - List(apiTagCounterparty, apiTagAccount), - Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty)) - ) - - lazy val getCounterpartyByIdForAnyAccount: OBPEndpoint = { - case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( - accountId - ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( - counterpartyId - ) :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user @ Full(u), _, account, callContext) <- SS.userBankAccount - (counterparty, callContext) <- NewStyle.function - .getCounterpartyByCounterpartyId(counterpartyId, callContext) - counterpartyMetadata <- NewStyle.function.getMetadata( - bankId, - accountId, - counterpartyId.value, - callContext - ) - } yield { - val counterpartyJson = - JSONFactory400.createCounterpartyWithMetadataJson400( - counterparty, - counterpartyMetadata - ) - (counterpartyJson, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - addConsentUser, - implementedInApiVersion, - nameOf(addConsentUser), - "PUT", - "/banks/BANK_ID/consents/CONSENT_ID/user-update-request", - "Add User to a Consent", - s""" - | - | - |This endpoint is used to add the User of Consent. - | - |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted - .mkString(", ")}. - | - |${userAuthenticationMessage(true)} - | - |""", - PutConsentUserJsonV400(user_id = "ed7a7c01-db37-45cc-ba12-0ae8891c195c"), - ConsentChallengeJsonV310( - consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945", - jwt = - "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4", - status = "AUTHORISED" - ), - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - $BankNotFound, - ConsentUserAlreadyAdded, - InvalidJsonFormat, - ConsentNotFound, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: Nil - ) - - lazy val addConsentUser: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "consents" :: consentId :: "user-update-request" :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- SS.user - failMsg = - s"$InvalidJsonFormat The Json body should be the $PutConsentUserJsonV400 " - putJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutConsentUserJsonV400] - } - user <- Users.users.vend.getUserByUserIdFuture( - putJson.user_id - ) map { x => - unboxFullOrFail( - x, - callContext, - s"$UserNotFoundByUserId Current UserId(${putJson.user_id})" - ) - } - consent <- Future( - Consents.consentProvider.vend.getConsentByConsentId(consentId) - ) map { i => - connectorEmptyResponse(i, callContext) - } - _ <- Helper.booleanToFuture( - ConsentUserAlreadyAdded, - cc = cc.callContext - ) { - Option(consent.userId).forall( - _.isBlank - ) // checks whether userId is not populated - } - consent <- Future( - Consents.consentProvider.vend.updateConsentUser(consentId, user) - ) map { i => - connectorEmptyResponse(i, callContext) - } - } yield { - ( - ConsentJsonV310( - consent.consentId, - consent.jsonWebToken, - consent.status - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateConsentStatus, - implementedInApiVersion, - nameOf(updateConsentStatus), - "PUT", - "/banks/BANK_ID/consents/CONSENT_ID", - "Update Consent Status", - s""" - | - | - |This endpoint is used to update the Status of Consent. - | - |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted - .mkString(", ")}. - | - |${userAuthenticationMessage(true)} - | - |""", - PutConsentStatusJsonV400(status = "AUTHORISED"), - ConsentChallengeJsonV310( - consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945", - jwt = - "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4", - status = "AUTHORISED" - ), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - InvalidJsonFormat, - InvalidConnectorResponse, - UnknownError - ), - apiTagConsent :: apiTagPSD2AIS :: Nil - ) - - lazy val updateConsentStatus: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "consents" :: consentId :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(user), callContext) <- SS.user - failMsg = - s"$InvalidJsonFormat The Json body should be the $PutConsentStatusJsonV400 " - consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[PutConsentStatusJsonV400] - } - consent <- Future( - Consents.consentProvider.vend.getConsentByConsentId(consentId) - ) map { i => - connectorEmptyResponse(i, callContext) - } - status = ConsentStatus.withName(consentJson.status) - (consent, code) <- APIUtil.getPropsAsBoolValue( - "consents.sca.enabled", - true - ) match { - case true => - Future(consent, HttpCode.`202`(callContext)) - case false => - Future( - Consents.consentProvider.vend - .updateConsentStatus(consentId, status) - ) map { i => - connectorEmptyResponse(i, callContext) - } map ((_, HttpCode.`200`(callContext))) - } - } yield { - ( - ConsentJsonV310( - consent.consentId, - consent.jsonWebToken, - consent.status - ), - code - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getConsents, - implementedInApiVersion, - nameOf(getConsents), - "GET", - "/banks/BANK_ID/my/consents", - "Get Consents", - s""" - | - |This endpoint gets the Consents that the current User created. - | - |${userAuthenticationMessage(true)} - | - |1 limit (for pagination: defaults to 50) eg:limit=200 - | - |2 offset (for pagination: zero index, defaults to 0) eg: offset=10 - | - """.stripMargin, - EmptyBody, - consentsJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) - ) - - lazy val getConsents: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val url = cc.url - val limitParam = getHttpRequestUrlParam(url, "limit") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50) - case _ => 50 - } - val offsetParam = getHttpRequestUrlParam(url, "offset") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0) - case _ => 0 - } - for { - rows <- Future { - DoobieConsentQueries.getConsentsByUserAndBank( - userId = cc.userId, - bankId = bankId.value, - status = None, - limit = limitParam, - offset = offsetParam, - sortField = "created_date", - sortDirection = "desc" - ) - } - } yield { - val consents = rows.map(r => ConsentJsonV400( - r.consentId, r.jwt.getOrElse(""), r.status, - r.apiStandard.getOrElse(""), r.apiVersion.getOrElse("") - )) - (ConsentsJsonV400(consents), HttpCode.`200`(cc)) - } - } - } - staticResourceDocs += ResourceDoc( - getConsentInfosByBank, - implementedInApiVersion, - nameOf(getConsentInfosByBank), - "GET", - "/banks/BANK_ID/my/consent-infos", - "Get My Consents Info At Bank", - s""" - | - |This endpoint gets the Consents that the current User created at bank. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - consentInfosJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) - ) - - lazy val getConsentInfosByBank: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "my" :: "consent-infos" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - consents <- Future { - Consents.consentProvider.vend - .getConsentsByUser(cc.userId) - .sortBy(i => (i.creationDateTime, i.apiStandard)) - .reverse - } - } yield { - val consentsOfBank = Consent.filterByBankId(consents, bankId) - ( - JSONFactory400.createConsentInfosJsonV400(consentsOfBank), - HttpCode.`200`(cc) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getConsentInfos, - implementedInApiVersion, - nameOf(getConsentInfos), - "GET", - "/my/consent-infos", - "Get My Consents Info", - s""" - | - |This endpoint gets the Consents that the current User created. - | - |${userAuthenticationMessage(true)} - | - """.stripMargin, - EmptyBody, - consentInfosJsonV400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) - ) - - lazy val getConsentInfos: OBPEndpoint = { - case "my" :: "consent-infos" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - consents <- Future { - Consents.consentProvider.vend - .getConsentsByUser(cc.userId) - .sortBy(i => (i.creationDateTime, i.apiStandard)) - .reverse - } - } yield { - ( - JSONFactory400.createConsentInfosJsonV400(consents), - HttpCode.`200`(cc) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyPersonalUserAttributes, - implementedInApiVersion, - nameOf(getMyPersonalUserAttributes), - "GET", - "/my/user/attributes", - "Get My Personal User Attributes", - s"""Get My Personal User Attributes. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - userAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagUser) - ) - - lazy val getMyPersonalUserAttributes: OBPEndpoint = { - case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributes, callContext) <- NewStyle.function - .getPersonalUserAttributes(cc.userId, cc.callContext) - } yield { - ( - JSONFactory400.createUserAttributesJson(attributes), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getUserWithAttributes, - implementedInApiVersion, - nameOf(getUserWithAttributes), - "GET", - "/users/USER_ID/attributes", - "Get User with Attributes by USER_ID", - s"""Get User Attributes for the user defined via USER_ID. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - userWithAttributesResponseJson, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagUser), - Some(canGetUsersWithAttributes :: Nil) - ) - - lazy val getUserWithAttributes: OBPEndpoint = { - case "users" :: userId :: "attributes" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (user, callContext) <- NewStyle.function.getUserByUserId( - userId, - cc.callContext - ) - (attributes, callContext) <- NewStyle.function.getUserAttributes( - user.userId, - callContext - ) - } yield { - ( - JSONFactory400.createUserWithAttributesJson(user, attributes), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createMyPersonalUserAttribute, - implementedInApiVersion, - nameOf(createMyPersonalUserAttribute), - "POST", - "/my/user/attributes", - "Create My Personal User Attribute", - s""" Create My Personal User Attribute - | - |The `type` field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - userAttributeJsonV400, - userAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagUser), - Some(List()) - ) - - lazy val createMyPersonalUserAttribute: OBPEndpoint = { - case "my" :: "user" :: "attributes" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val failMsg = - s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 " - for { - postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { - json.extract[UserAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${TransactionAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)" - userAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - cc.callContext - ) { - UserAttributeType.withName(postedData.`type`) - } - (userAttribute, callContext) <- NewStyle.function - .createOrUpdateUserAttribute( - cc.userId, - None, - postedData.name, - userAttributeType, - postedData.value, - true, - cc.callContext - ) - } yield { - ( - JSONFactory400.createUserAttributeJson(userAttribute), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateMyPersonalUserAttribute, - implementedInApiVersion, - nameOf(updateMyPersonalUserAttribute), - "PUT", - "/my/user/attributes/USER_ATTRIBUTE_ID", - "Update My Personal User Attribute", - s"""Update My Personal User Attribute for current user by USER_ATTRIBUTE_ID - | - |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" - | - |${userAuthenticationMessage(true)} - | - |""", - userAttributeJsonV400, - userAttributeResponseJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagUser), - Some(List()) - ) - - lazy val updateMyPersonalUserAttribute: OBPEndpoint = { - case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (attributes, callContext) <- NewStyle.function - .getPersonalUserAttributes(cc.userId, cc.callContext) - failMsg = s"$UserAttributeNotFound" - _ <- NewStyle.function.tryons(failMsg, 400, callContext) { - attributes.exists(_.userAttributeId == userAttributeId) - } - postedData <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 ", - 400, - callContext - ) { - json.extract[UserAttributeJsonV400] - } - failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + - s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)" - userAttributeType <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - UserAttributeType.withName(postedData.`type`) - } - (userAttribute, callContext) <- NewStyle.function - .createOrUpdateUserAttribute( - cc.userId, - Some(userAttributeId), - postedData.name, - userAttributeType, - postedData.value, - true, - callContext - ) - } yield { - ( - JSONFactory400.createUserAttributeJson(userAttribute), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getScannedApiVersions, - implementedInApiVersion, - nameOf(getScannedApiVersions), - "GET", - "/api/versions", - "Get scanned API Versions", - s"""Get all the scanned API Versions.""", - EmptyBody, - ListResult( - "scanned_api_versions", - List(Extraction.decompose(ApiVersion.v3_1_0)) - ), - List( - UnknownError - ), - List(apiTagDocumentation, apiTagApi), - Some(Nil) - ) - - lazy val getScannedApiVersions: OBPEndpoint = { - case "api" :: "versions" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - Future { - val versions: List[ScannedApiVersion] = - ApiVersion.allScannedApiVersion.asScala.toList.filter { version => - version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version) - } - ( - ListResult("scanned_api_versions", versions), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createMyApiCollection, - implementedInApiVersion, - nameOf(createMyApiCollection), - "POST", - "/my/api-collections", - "Create My Api Collection", - s"""Create Api Collection for logged in user. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - postApiCollectionJson400, - apiCollectionJson400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val createMyApiCollection: OBPEndpoint = { - case "my" :: "api-collections" :: Nil JsonPost json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostApiCollectionJson400", - 400, - cc.callContext - ) { - json.extract[PostApiCollectionJson400] - } - apiCollection <- Future { - MappedApiCollectionsProvider - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - postJson.api_collection_name - ) - } - _ <- Helper.booleanToFuture( - failMsg = - s"$ApiCollectionAlreadyExists Current api_collection_name(${postJson.api_collection_name}) is already existing for the log in user.", - cc = cc.callContext - ) { - apiCollection.isEmpty - } - (apiCollection, callContext) <- NewStyle.function.createApiCollection( - cc.userId, - postJson.api_collection_name, - postJson.is_sharable, - postJson.description.getOrElse(""), - Some(cc) - ) - } yield { - ( - JSONFactory400.createApiCollectionJsonV400(apiCollection), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollectionByName, - implementedInApiVersion, - nameOf(getMyApiCollectionByName), - "GET", - "/my/api-collections/name/API_COLLECTION_NAME", - "Get My Api Collection By Name", - s"""Get Api Collection By API_COLLECTION_NAME. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - apiCollectionJson400, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollectionByName: OBPEndpoint = { - case "my" :: "api-collections" :: "name" :: apiCollectionName :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - apiCollectionName, - Some(cc) - ) - } yield { - ( - JSONFactory400.createApiCollectionJsonV400(apiCollection), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollectionById, - implementedInApiVersion, - nameOf(getMyApiCollectionById), - "GET", - "/my/api-collections/API_COLLECTION_ID", - "Get My Api Collection By Id", - s"""Get Api Collection By API_COLLECTION_ID. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - apiCollectionJson400, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollectionById: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - } yield { - ( - JSONFactory400.createApiCollectionJsonV400(apiCollection), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getSharableApiCollectionById, - implementedInApiVersion, - nameOf(getSharableApiCollectionById), - "GET", - "/api-collections/sharable/API_COLLECTION_ID", - "Get Sharable Api Collection By Id", - s"""Get Sharable Api Collection By Id. - |${userAuthenticationMessage(false)} - |""".stripMargin, - EmptyBody, - apiCollectionJson400, - List( - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getSharableApiCollectionById: OBPEndpoint = { - case "api-collections" :: "sharable" :: apiCollectionId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, cc.callContext) - _ <- Helper.booleanToFuture( - failMsg = - s"$ApiCollectionEndpointNotFound Current api_collection_id(${apiCollectionId}) is not sharable.", - cc = callContext - ) { - apiCollection.isSharable - } - } yield { - ( - JSONFactory400.createApiCollectionJsonV400(apiCollection), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getApiCollectionsForUser, - implementedInApiVersion, - nameOf(getApiCollectionsForUser), - "GET", - "/users/USER_ID/api-collections", - "Get Api Collections for User", - s"""Get Api Collections for User. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - apiCollectionsJson400, - List( - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection), - Some(canGetApiCollectionsForUser :: Nil) - ) - - lazy val getApiCollectionsForUser: OBPEndpoint = { - case "users" :: userId :: "api-collections" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.findByUserId(userId, Some(cc)) - (apiCollections, callContext) <- NewStyle.function - .getApiCollectionsByUserId(userId, callContext) - } yield { - ( - JSONFactory400.createApiCollectionsJsonV400(apiCollections), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getFeaturedApiCollections, - implementedInApiVersion, - nameOf(getFeaturedApiCollections), - "GET", - "/api-collections/featured", - "Get Featured Api Collections", - s"""Get Featured Api Collections. - | - |${userAuthenticationMessage(false)} - |""".stripMargin, - EmptyBody, - apiCollectionsJson400, - List( - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getFeaturedApiCollections: OBPEndpoint = { - case "api-collections" :: "featured" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollections, callContext) <- NewStyle.function - .getFeaturedApiCollections(cc.callContext) - } yield { - ( - JSONFactory400.createApiCollectionsJsonV400(apiCollections), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollections, - implementedInApiVersion, - nameOf(getMyApiCollections), - "GET", - "/my/api-collections", - "Get My Api Collections", - s"""Get all the apiCollections for logged in user. - | - |${userAuthenticationMessage(true)} - | - |1 limit (for pagination: defaults to 50) eg:limit=200 - | - |2 offset (for pagination: zero index, defaults to 0) eg: offset=10 - | - |""".stripMargin, - EmptyBody, - apiCollectionsJson400, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollections: OBPEndpoint = { - case "my" :: "api-collections" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val url = cc.url - val limitParam = getHttpRequestUrlParam(url, "limit") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50) - case _ => 50 - } - val offsetParam = getHttpRequestUrlParam(url, "offset") match { - case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0) - case _ => 0 - } - for { - (apiCollections, callContext) <- NewStyle.function - .getApiCollectionsByUserId(cc.userId, Some(cc)) - } yield { - val paginated = apiCollections.drop(offsetParam).take(limitParam) - ( - JSONFactory400.createApiCollectionsJsonV400(paginated), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyApiCollection, - implementedInApiVersion, - nameOf(deleteMyApiCollection), - "DELETE", - "/my/api-collections/API_COLLECTION_ID", - "Delete My Api Collection", - s"""Delete Api Collection By API_COLLECTION_ID - | - |${Glossary.getGlossaryItem("API Collections")} - | - |${userAuthenticationMessage(true)} - | - | - | - |""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val deleteMyApiCollection: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - (deleted, callContext) <- NewStyle.function.deleteApiCollectionById( - apiCollectionId, - callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createMyApiCollectionEndpoint, - implementedInApiVersion, - nameOf(createMyApiCollectionEndpoint), - "POST", - "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints", - "Create My Api Collection Endpoint", - s"""Create Api Collection Endpoint. - | - |${Glossary.getGlossaryItem("API Collections")} - | - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - postApiCollectionEndpointJson400, - apiCollectionEndpointJson400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val createMyApiCollectionEndpoint: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400", - 400, - cc.callContext - ) { - json.extract[PostApiCollectionEndpointJson400] - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})", - cc = Some(cc) - ) { - getAllResourceDocs - .find(_.operationId == postJson.operation_id.trim) - .isDefined - } - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - apiCollectionName, - Some(cc) - ) - apiCollectionEndpoint <- Future { - MappedApiCollectionEndpointsProvider - .getApiCollectionEndpointByApiCollectionIdAndOperationId( - apiCollection.apiCollectionId, - postJson.operation_id - ) - } - _ <- Helper.booleanToFuture( - failMsg = - s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_NAME($apiCollectionName) ", - cc = callContext - ) { - apiCollectionEndpoint.isEmpty - } - (apiCollectionEndpoint, callContext) <- NewStyle.function - .createApiCollectionEndpoint( - apiCollection.apiCollectionId, - postJson.operation_id, - callContext - ) - } yield { - ( - JSONFactory400.createApiCollectionEndpointJsonV400( - apiCollectionEndpoint - ), - HttpCode.`201`(callContext) - ) - } - } - } - staticResourceDocs += ResourceDoc( - createMyApiCollectionEndpointById, - implementedInApiVersion, - nameOf(createMyApiCollectionEndpointById), - "POST", - "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints", - "Create My Api Collection Endpoint By Id", - s"""Create Api Collection Endpoint By Id. - | - |${Glossary.getGlossaryItem("API Collections")} - | - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - postApiCollectionEndpointJson400, - apiCollectionEndpointJson400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val createMyApiCollectionEndpointById: OBPEndpoint = { - case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - postJson <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400", - 400, - cc.callContext - ) { - json.extract[PostApiCollectionEndpointJson400] - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})", - cc = Some(cc) - ) { - getAllResourceDocs - .find(_.operationId == postJson.operation_id.trim) - .isDefined - } - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - apiCollectionEndpoint <- Future { - MappedApiCollectionEndpointsProvider - .getApiCollectionEndpointByApiCollectionIdAndOperationId( - apiCollection.apiCollectionId, - postJson.operation_id - ) - } - _ <- Helper.booleanToFuture( - failMsg = - s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_ID($apiCollectionId) ", - cc = callContext - ) { - apiCollectionEndpoint.isEmpty - } - (apiCollectionEndpoint, callContext) <- NewStyle.function - .createApiCollectionEndpoint( - apiCollection.apiCollectionId, - postJson.operation_id, - callContext - ) - } yield { - ( - JSONFactory400.createApiCollectionEndpointJsonV400( - apiCollectionEndpoint - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollectionEndpoint, - implementedInApiVersion, - nameOf(getMyApiCollectionEndpoint), - "GET", - "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID", - "Get My Api Collection Endpoint", - s"""Get Api Collection Endpoint By API_COLLECTION_NAME and OPERATION_ID. - | - |${userAuthenticationMessage(false)} - |""".stripMargin, - EmptyBody, - apiCollectionEndpointJson400, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollectionEndpoint: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - apiCollectionName, - Some(cc) - ) - (apiCollectionEndpoint, callContext) <- NewStyle.function - .getApiCollectionEndpointByApiCollectionIdAndOperationId( - apiCollection.apiCollectionId, - operationId, - Some(cc) - ) - } yield { - ( - JSONFactory400.createApiCollectionEndpointJsonV400( - apiCollectionEndpoint - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getApiCollectionEndpoints, - implementedInApiVersion, - nameOf(getApiCollectionEndpoints), - "GET", - "/api-collections/API_COLLECTION_ID/api-collection-endpoints", - "Get Api Collection Endpoints", - s"""Get Api Collection Endpoints By API_COLLECTION_ID. - | - |${userAuthenticationMessage(false)} - |""".stripMargin, - EmptyBody, - apiCollectionEndpointsJson400, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getApiCollectionEndpoints: OBPEndpoint = { - case "api-collections" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollectionEndpoints, callContext) <- NewStyle.function - .getApiCollectionEndpoints(apiCollectionId, Some(cc)) - } yield { - ( - JSONFactory400.createApiCollectionEndpointsJsonV400( - apiCollectionEndpoints - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollectionEndpoints, - implementedInApiVersion, - nameOf(getMyApiCollectionEndpoints), - "GET", - "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints", - "Get My Api Collection Endpoints", - s"""Get Api Collection Endpoints By API_COLLECTION_NAME. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - apiCollectionEndpointsJson400, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollectionEndpoints: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - apiCollectionName, - Some(cc) - ) - (apiCollectionEndpoints, callContext) <- NewStyle.function - .getApiCollectionEndpoints( - apiCollection.apiCollectionId, - callContext - ) - } yield { - ( - JSONFactory400.createApiCollectionEndpointsJsonV400( - apiCollectionEndpoints - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getMyApiCollectionEndpointsById, - implementedInApiVersion, - nameOf(getMyApiCollectionEndpointsById), - "GET", - "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints", - "Get My Api Collection Endpoints By Id", - s"""Get Api Collection Endpoints By API_COLLECTION_ID. - | - |${userAuthenticationMessage(true)} - |""".stripMargin, - EmptyBody, - apiCollectionEndpointsJson400, - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val getMyApiCollectionEndpointsById: OBPEndpoint = { - case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - (apiCollectionEndpoints, callContext) <- NewStyle.function - .getApiCollectionEndpoints( - apiCollection.apiCollectionId, - callContext - ) - } yield { - ( - JSONFactory400.createApiCollectionEndpointsJsonV400( - apiCollectionEndpoints - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyApiCollectionEndpoint, - implementedInApiVersion, - nameOf(deleteMyApiCollectionEndpoint), - "DELETE", - "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID", - "Delete My Api Collection Endpoint", - s"""${Glossary.getGlossaryItem("API Collections")} - | - | - |Delete Api Collection Endpoint By OPERATION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val deleteMyApiCollectionEndpoint: OBPEndpoint = { - case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionByUserIdAndCollectionName( - cc.userId, - apiCollectionName, - Some(cc) - ) - (apiCollectionEndpoint, callContext) <- NewStyle.function - .getApiCollectionEndpointByApiCollectionIdAndOperationId( - apiCollection.apiCollectionId, - operationId, - callContext - ) - (deleted, callContext) <- NewStyle.function - .deleteApiCollectionEndpointById( - apiCollectionEndpoint.apiCollectionEndpointId, - callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyApiCollectionEndpointByOperationId, - implementedInApiVersion, - nameOf(deleteMyApiCollectionEndpointByOperationId), - "DELETE", - "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints/OPERATION_ID", - "Delete My Api Collection Endpoint By Id", - s"""${Glossary.getGlossaryItem("API Collections")} - | - |Delete Api Collection Endpoint By OPERATION_ID - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val deleteMyApiCollectionEndpointByOperationId: OBPEndpoint = { - case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - (apiCollectionEndpoint, callContext) <- NewStyle.function - .getApiCollectionEndpointByApiCollectionIdAndOperationId( - apiCollection.apiCollectionId, - operationId, - callContext - ) - (deleted, callContext) <- NewStyle.function - .deleteApiCollectionEndpointById( - apiCollectionEndpoint.apiCollectionEndpointId, - callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteMyApiCollectionEndpointById, - implementedInApiVersion, - nameOf(deleteMyApiCollectionEndpointById), - "DELETE", - "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoint-ids/API_COLLECTION_ENDPOINT_ID", - "Delete My Api Collection Endpoint By Id", - s"""${Glossary.getGlossaryItem("API Collections")} - |Delete Api Collection Endpoint - |Delete Api Collection Endpoint By Id - | - |${userAuthenticationMessage(true)} - | - |""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - UserNotFoundByUserId, - UnknownError - ), - List(apiTagApiCollection) - ) - - lazy val deleteMyApiCollectionEndpointById: OBPEndpoint = { - case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoint-ids" :: apiCollectionEndpointId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (apiCollection, callContext) <- NewStyle.function - .getApiCollectionById(apiCollectionId, Some(cc)) - (apiCollectionEndpoint, callContext) <- NewStyle.function - .getApiCollectionEndpointById( - apiCollectionEndpointId, - callContext - ) - (deleted, callContext) <- NewStyle.function - .deleteApiCollectionEndpointById( - apiCollectionEndpoint.apiCollectionEndpointId, - callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createJsonSchemaValidation, - implementedInApiVersion, - nameOf(createJsonSchemaValidation), - "POST", - "/management/json-schema-validations/OPERATION_ID", - "Create a JSON Schema Validation", - s"""Create a JSON Schema Validation. - | - |Introduction: - |${Glossary.getGlossaryItemSimple("JSON Schema Validation")} - | - |To use this endpoint, please supply a valid json-schema in the request body. - | - |Note: It might take a few minutes for the newly created JSON Schema to take effect! - |""", - postOrPutJsonSchemaV400, - responseJsonSchema, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - Some(List(canCreateJsonSchemaValidation)) - ) - - lazy val createJsonSchemaValidation: OBPEndpoint = { - case "management" :: "json-schema-validations" :: operationId :: Nil JsonPost _ -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val httpBody: String = cc.httpBody.getOrElse("") - for { - (Full(u), callContext) <- SS.user - - schemaErrors: util.Set[ValidationMessage] = JsonSchemaUtil - .validateSchema(httpBody) - _ <- Helper.booleanToFuture( - failMsg = - s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", - cc = callContext - ) { - CommonUtil.Collections.isEmpty(schemaErrors) - } - - (isExists, callContext) <- NewStyle.function - .isJsonSchemaValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = OperationIdExistsError, - cc = callContext - ) { - !isExists - } - (validation, callContext) <- NewStyle.function - .createJsonSchemaValidation( - JsonValidation(operationId, httpBody), - callContext - ) - } yield { - (validation, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateJsonSchemaValidation, - implementedInApiVersion, - nameOf(updateJsonSchemaValidation), - "PUT", - "/management/json-schema-validations/OPERATION_ID", - "Update a JSON Schema Validation", - s"""Update a JSON Schema Validation. - | - |Introduction: - |${Glossary.getGlossaryItemSimple("JSON Schema Validation")} - | - |To use this endpoint, please supply a valid json-schema in the request body. - | - |""", - postOrPutJsonSchemaV400, - responseJsonSchema, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - Some(List(canUpdateJsonSchemaValidation)) - ) - - lazy val updateJsonSchemaValidation: OBPEndpoint = { - case "management" :: "json-schema-validations" :: operationId :: Nil JsonPut _ -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - val httpBody: String = cc.httpBody.getOrElse("") - for { - (Full(u), callContext) <- SS.user - - schemaErrors = JsonSchemaUtil.validateSchema(httpBody) - _ <- Helper.booleanToFuture( - failMsg = - s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", - cc = callContext - ) { - CommonUtil.Collections.isEmpty(schemaErrors) - } - - (isExists, callContext) <- NewStyle.function - .isJsonSchemaValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = JsonSchemaValidationNotFound, - cc = callContext - ) { - isExists - } - (validation, callContext) <- NewStyle.function - .updateJsonSchemaValidation(operationId, httpBody, callContext) - } yield { - (validation, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteJsonSchemaValidation, - implementedInApiVersion, - nameOf(deleteJsonSchemaValidation), - "DELETE", - "/management/json-schema-validations/OPERATION_ID", - "Delete a JSON Schema Validation", - s"""Delete a JSON Schema Validation by operation_id. - | - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - Some(List(canDeleteJsonSchemaValidation)) - ) - - lazy val deleteJsonSchemaValidation: OBPEndpoint = { - case "management" :: "json-schema-validations" :: operationId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - - (isExists, callContext) <- NewStyle.function - .isJsonSchemaValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = JsonSchemaValidationNotFound, - cc = callContext - ) { - isExists - } - - (deleteResult, callContext) <- NewStyle.function - .deleteJsonSchemaValidation(operationId, callContext) - } yield { - (deleteResult, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getJsonSchemaValidation, - implementedInApiVersion, - nameOf(getJsonSchemaValidation), - "GET", - "/management/json-schema-validations/OPERATION_ID", - "Get a JSON Schema Validation", - s"""Get a JSON Schema Validation by operation_id. - | - |""", - EmptyBody, - responseJsonSchema, - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - Some(List(canGetJsonSchemaValidation)) - ) - - lazy val getJsonSchemaValidation: OBPEndpoint = { - case "management" :: "json-schema-validations" :: operationId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (validation, callContext) <- NewStyle.function - .getJsonSchemaValidationByOperationId(operationId, cc.callContext) - } yield { - (validation, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllJsonSchemaValidations, - implementedInApiVersion, - nameOf(getAllJsonSchemaValidations), - "GET", - "/management/json-schema-validations", - "Get all JSON Schema Validations", - s"""Get all JSON Schema Validations. - | - |""", - EmptyBody, - ListResult("json_schema_validations", responseJsonSchema :: Nil), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - Some(List(canGetJsonSchemaValidation)) - ) - - lazy val getAllJsonSchemaValidations: OBPEndpoint = { - case ("management" | - "endpoints") :: "json-schema-validations" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (jsonSchemaValidations, callContext) <- NewStyle.function - .getJsonSchemaValidations(cc.callContext) - } yield { - ( - ListResult("json_schema_validations", jsonSchemaValidations), - HttpCode.`200`(callContext) - ) - } - } - } - - private val jsonSchemaValidationRequiresRole: Boolean = APIUtil - .getPropsAsBoolValue("read_json_schema_validation_requires_role", false) - lazy val getAllJsonSchemaValidationsPublic = getAllJsonSchemaValidations - - staticResourceDocs += ResourceDoc( - getAllJsonSchemaValidationsPublic, - implementedInApiVersion, - nameOf(getAllJsonSchemaValidationsPublic), - "GET", - "/endpoints/json-schema-validations", - "Get all JSON Schema Validations - public", - s"""Get all JSON Schema Validations - public. - | - |""", - EmptyBody, - ListResult("json_schema_validations", responseJsonSchema :: Nil), - (if (jsonSchemaValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil) - ::: List( - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagJsonSchemaValidation), - None - ) - - // auth type validation related endpoints - private val allowedAuthTypes = - AuthenticationType.values.filterNot(AuthenticationType.Anonymous.==) - staticResourceDocs += ResourceDoc( - createAuthenticationTypeValidation, - implementedInApiVersion, - nameOf(createAuthenticationTypeValidation), - "POST", - "/management/authentication-type-validations/OPERATION_ID", - "Create an Authentication Type Validation", - s"""Create an Authentication Type Validation. - | - |Please supply allowed authentication types. - |""", - allowedAuthTypes, - JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - Some(List(canCreateAuthenticationTypeValidation)) - ) - - lazy val createAuthenticationTypeValidation: OBPEndpoint = { - case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPost jArray -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - - authTypes <- NewStyle.function.tryons( - s"$AuthenticationTypeNameIllegal Allowed Authentication Type names: ${allowedAuthTypes - .mkString("[", ", ", "]")}", - 400, - cc.callContext - ) { - jArray.extract[List[AuthenticationType]] - } - - (isExists, callContext) <- NewStyle.function - .isAuthenticationTypeValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = OperationIdExistsError, - cc = callContext - ) { - !isExists - } - (authenticationTypeValidation, callContext) <- NewStyle.function - .createAuthenticationTypeValidation( - JsonAuthTypeValidation(operationId, authTypes), - callContext - ) - } yield { - (authenticationTypeValidation, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAuthenticationTypeValidation, - implementedInApiVersion, - nameOf(updateAuthenticationTypeValidation), - "PUT", - "/management/authentication-type-validations/OPERATION_ID", - "Update an Authentication Type Validation", - s"""Update an Authentication Type Validation. - | - |Please supply allowed authentication types. - |""", - allowedAuthTypes, - JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - Some(List(canUpdateAuthenticationTypeValidation)) - ) - - lazy val updateAuthenticationTypeValidation: OBPEndpoint = { - case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPut jArray -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - - authTypes <- NewStyle.function.tryons( - s"$AuthenticationTypeNameIllegal Allowed AuthenticationType names: ${allowedAuthTypes - .mkString("[", ", ", "]")}", - 400, - cc.callContext - ) { - jArray.extract[List[AuthenticationType]] - } - - (isExists, callContext) <- NewStyle.function - .isAuthenticationTypeValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = AuthenticationTypeValidationNotFound, - cc = callContext - ) { - isExists - } - (authenticationTypeValidation, callContext) <- NewStyle.function - .updateAuthenticationTypeValidation( - operationId, - authTypes, - callContext - ) - } yield { - (authenticationTypeValidation, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteAuthenticationTypeValidation, - implementedInApiVersion, - nameOf(deleteAuthenticationTypeValidation), - "DELETE", - "/management/authentication-type-validations/OPERATION_ID", - "Delete an Authentication Type Validation", - s"""Delete an Authentication Type Validation by operation_id. - | - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - Some(List(canDeleteAuthenticationValidation)) - ) - - lazy val deleteAuthenticationTypeValidation: OBPEndpoint = { - case "management" :: "authentication-type-validations" :: operationId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - - (isExists, callContext) <- NewStyle.function - .isAuthenticationTypeValidationExists(operationId, callContext) - _ <- Helper.booleanToFuture( - failMsg = AuthenticationTypeValidationNotFound, - cc = callContext - ) { - isExists - } - - (deleteResult, callContext) <- NewStyle.function - .deleteAuthenticationTypeValidation(operationId, callContext) - } yield { - (deleteResult, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAuthenticationTypeValidation, - implementedInApiVersion, - nameOf(getAuthenticationTypeValidation), - "GET", - "/management/authentication-type-validations/OPERATION_ID", - "Get an Authentication Type Validation", - s"""Get an Authentication Type Validation by operation_id. - | - |""", - EmptyBody, - JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), - List( - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - Some(List(canGetAuthenticationTypeValidation)) - ) - - lazy val getAuthenticationTypeValidation: OBPEndpoint = { - case "management" :: "authentication-type-validations" :: operationId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (authenticationTypeValidation, callContext) <- NewStyle.function - .getAuthenticationTypeValidationByOperationId( - operationId, - cc.callContext - ) - } yield { - (authenticationTypeValidation, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllAuthenticationTypeValidations, - implementedInApiVersion, - nameOf(getAllAuthenticationTypeValidations), - "GET", - "/management/authentication-type-validations", - "Get all Authentication Type Validations", - s"""Get all Authentication Type Validations. - | - |""", - EmptyBody, - ListResult( - "authentication_types_validations", - List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes)) - ), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - Some(List(canGetAuthenticationTypeValidation)) - ) - - lazy val getAllAuthenticationTypeValidations: OBPEndpoint = { - case ("management" | - "endpoints") :: "authentication-type-validations" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (authenticationTypeValidations, callContext) <- NewStyle.function - .getAuthenticationTypeValidations(cc.callContext) - } yield { - ( - ListResult( - "authentication_types_validations", - authenticationTypeValidations - ), - HttpCode.`200`(callContext) - ) - } - } - } - - private val authenticationTypeValidationRequiresRole: Boolean = - APIUtil.getPropsAsBoolValue( - "read_authentication_type_validation_requires_role", - false - ) - lazy val getAllAuthenticationTypeValidationsPublic = - getAllAuthenticationTypeValidations - - staticResourceDocs += ResourceDoc( - getAllAuthenticationTypeValidationsPublic, - implementedInApiVersion, - nameOf(getAllAuthenticationTypeValidationsPublic), - "GET", - "/endpoints/authentication-type-validations", - "Get all Authentication Type Validations - public", - s"""Get all Authentication Type Validations - public. - | - |""", - EmptyBody, - ListResult( - "authentication_types_validations", - List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes)) - ), - (if (authenticationTypeValidationRequiresRole) List($AuthenticatedUserIsRequired) - else Nil) - ::: List( - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagAuthenticationTypeValidation), - None - ) - - staticResourceDocs += ResourceDoc( - createConnectorMethod, - implementedInApiVersion, - nameOf(createConnectorMethod), - "POST", - "/management/connector-methods", - "Create Connector Method", - s"""Create an internal connector. - | - |The method_body is URL-encoded format String - |""", - jsonScalaConnectorMethod.copy(connectorMethodId = None), - jsonScalaConnectorMethod, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagConnectorMethod), - Some(List(canCreateConnectorMethod)) - ) - - lazy val createConnectorMethod: OBPEndpoint = { - case "management" :: "connector-methods" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - jsonConnectorMethod <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod", - 400, - cc.callContext - ) { - json.extract[JsonConnectorMethod] - } - - (isExists, callContext) <- NewStyle.function - .connectorMethodNameExists( - jsonConnectorMethod.methodName, - Some(cc) - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$ConnectorMethodAlreadyExists Please use a different method_name(${jsonConnectorMethod.methodName})", - cc = callContext - ) { - (!isExists) - } - connectorMethod = InternalConnector.createFunction( - jsonConnectorMethod.methodName, - jsonConnectorMethod.decodedMethodBody, - jsonConnectorMethod.programmingLang - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.head) - (connectorMethod, callContext) <- NewStyle.function - .createJsonConnectorMethod(jsonConnectorMethod, callContext) - } yield { - (connectorMethod, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateConnectorMethod, - implementedInApiVersion, - nameOf(updateConnectorMethod), - "PUT", - "/management/connector-methods/CONNECTOR_METHOD_ID", - "Update Connector Method", - s"""Update an internal connector. - | - |The method_body is URL-encoded format String - |""", - jsonScalaConnectorMethodMethodBody, - jsonScalaConnectorMethod, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagConnectorMethod), - Some(List(canUpdateConnectorMethod)) - ) - - lazy val updateConnectorMethod: OBPEndpoint = { - case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - connectorMethodBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod", - 400, - cc.callContext - ) { - json.extract[JsonConnectorMethodMethodBody] - } - - (cm, callContext) <- NewStyle.function.getJsonConnectorMethodById( - connectorMethodId, - cc.callContext - ) - - connectorMethod = InternalConnector.createFunction( - cm.methodName, - connectorMethodBody.decodedMethodBody, - connectorMethodBody.programmingLang - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.head) - (connectorMethod, callContext) <- NewStyle.function - .updateJsonConnectorMethod( - connectorMethodId, - connectorMethodBody.methodBody, - connectorMethodBody.programmingLang, - callContext - ) - } yield { - (connectorMethod, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getConnectorMethod, - implementedInApiVersion, - nameOf(getConnectorMethod), - "GET", - "/management/connector-methods/CONNECTOR_METHOD_ID", - "Get Connector Method by Id", - s"""Get an internal connector by CONNECTOR_METHOD_ID. - | - |""", - EmptyBody, - jsonScalaConnectorMethod, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagConnectorMethod), - Some(List(canGetConnectorMethod)) - ) - - lazy val getConnectorMethod: OBPEndpoint = { - case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (connectorMethod, callContext) <- NewStyle.function - .getJsonConnectorMethodById(connectorMethodId, cc.callContext) - } yield { - (connectorMethod, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllConnectorMethods, - implementedInApiVersion, - nameOf(getAllConnectorMethods), - "GET", - "/management/connector-methods", - "Get all Connector Methods", - s"""Get all Connector Methods. - | - |""", - EmptyBody, - ListResult("connectors_methods", jsonScalaConnectorMethod :: Nil), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagConnectorMethod), - Some(List(canGetAllConnectorMethods)) - ) - - lazy val getAllConnectorMethods: OBPEndpoint = { - case "management" :: "connector-methods" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (connectorMethods, callContext) <- NewStyle.function - .getJsonConnectorMethods(cc.callContext) - } yield { - ( - ListResult("connector_methods", connectorMethods), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createDynamicResourceDoc, - implementedInApiVersion, - nameOf(createDynamicResourceDoc), - "POST", - "/management/dynamic-resource-docs", - "Create Dynamic Resource Doc", - s"""Create a Dynamic Resource Doc. - | - |The connector_method_body is URL-encoded format String - |""", - jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), - jsonDynamicResourceDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canCreateDynamicResourceDoc)) - ) - - lazy val createDynamicResourceDoc: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - jsonDynamicResourceDoc <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicResourceDoc] - } - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", - cc = cc.callContext - ) { - Set("POST", "PUT", "GET", "DELETE").contains( - jsonDynamicResourceDoc.requestVerb - ) - } - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""", - cc = cc.callContext - ) { - ( - jsonDynamicResourceDoc.requestVerb, - jsonDynamicResourceDoc.exampleRequestBody - ) match { - case ( - "GET" | "DELETE", - Some(JString(s)) - ) => // we support the empty string "" here - StringUtils.isBlank(s) - case ( - "GET" | "DELETE", - Some(requestBody) - ) => // we add the guard, we forbid any json objects in GET/DELETE request body. - requestBody == JNothing - case _ => true - } - } - _ = - try { - CompiledObjects( - jsonDynamicResourceDoc.exampleRequestBody, - jsonDynamicResourceDoc.successResponseBody, - jsonDynamicResourceDoc.methodBody - ) - .validateDependency() - } catch { - case e: JsonResponseException => - throw e - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - - (isExists, callContext) <- NewStyle.function - .isJsonDynamicResourceDocExists( - None, - jsonDynamicResourceDoc.requestVerb, - jsonDynamicResourceDoc.requestUrl, - Some(cc) - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", - cc = callContext - ) { - (!isExists) - } - - (dynamicResourceDoc, callContext) <- NewStyle.function - .createJsonDynamicResourceDoc( - None, - jsonDynamicResourceDoc, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateDynamicResourceDoc, - implementedInApiVersion, - nameOf(updateDynamicResourceDoc), - "PUT", - "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Update Dynamic Resource Doc", - s"""Update a Dynamic Resource Doc. - | - |The connector_method_body is URL-encoded format String - |""", - jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), - jsonDynamicResourceDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canUpdateDynamicResourceDoc)) - ) - - lazy val updateDynamicResourceDoc: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicResourceDocBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicResourceDoc] - } - - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", - cc = cc.callContext - ) { - Set("POST", "PUT", "GET", "DELETE").contains( - dynamicResourceDocBody.requestVerb - ) - } - - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", - cc = cc.callContext - ) { - ( - dynamicResourceDocBody.requestVerb, - dynamicResourceDocBody.exampleRequestBody - ) match { - case ("GET" | "DELETE", Some(JString(s))) => - StringUtils.isBlank(s) - case ("GET" | "DELETE", Some(requestBody)) => - requestBody == JNothing - case _ => true - } - } - - _ = - try { - CompiledObjects( - jsonDynamicResourceDoc.exampleRequestBody, - jsonDynamicResourceDoc.successResponseBody, - jsonDynamicResourceDoc.methodBody - ) - .validateDependency() - } catch { - case e: JsonResponseException => - throw e - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( - None, - dynamicResourceDocId, - cc.callContext - ) - - (dynamicResourceDoc, callContext) <- NewStyle.function - .updateJsonDynamicResourceDoc( - None, - dynamicResourceDocBody.copy(dynamicResourceDocId = - Some(dynamicResourceDocId) - ), - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteDynamicResourceDoc, - implementedInApiVersion, - nameOf(deleteDynamicResourceDoc), - "DELETE", - "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Delete Dynamic Resource Doc", - s"""Delete a Dynamic Resource Doc. - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canDeleteDynamicResourceDoc)) - ) - - lazy val deleteDynamicResourceDoc: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( - None, - dynamicResourceDocId, - cc.callContext - ) - (dynamicResourceDoc, callContext) <- NewStyle.function - .deleteJsonDynamicResourceDocById( - None, - dynamicResourceDocId, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getDynamicResourceDoc, - implementedInApiVersion, - nameOf(getDynamicResourceDoc), - "GET", - "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Get Dynamic Resource Doc by Id", - s"""Get a Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID. - | - |""", - EmptyBody, - jsonDynamicResourceDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canGetDynamicResourceDoc)) - ) - - lazy val getDynamicResourceDoc: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicResourceDoc, callContext) <- NewStyle.function - .getJsonDynamicResourceDocById( - None, - dynamicResourceDocId, - cc.callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllDynamicResourceDocs, - implementedInApiVersion, - nameOf(getAllDynamicResourceDocs), - "GET", - "/management/dynamic-resource-docs", - "Get all Dynamic Resource Docs", - s"""Get all Dynamic Resource Docs. - | - |""", - EmptyBody, - ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canGetAllDynamicResourceDocs)) - ) - - lazy val getAllDynamicResourceDocs: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicResourceDocs, callContext) <- NewStyle.function - .getJsonDynamicResourceDocs(None, cc.callContext) - } yield { - ( - ListResult("dynamic-resource-docs", dynamicResourceDocs), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createBankLevelDynamicResourceDoc, - implementedInApiVersion, - nameOf(createBankLevelDynamicResourceDoc), - "POST", - "/management/banks/BANK_ID/dynamic-resource-docs", - "Create Bank Level Dynamic Resource Doc", - s"""Create a Bank Level Dynamic Resource Doc. - | - |The connector_method_body is URL-encoded format String - |""", - jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), - jsonDynamicResourceDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canCreateBankLevelDynamicResourceDoc)) - ) - - lazy val createBankLevelDynamicResourceDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - jsonDynamicResourceDoc <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicResourceDoc] - } - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", - cc = cc.callContext - ) { - Set("POST", "PUT", "GET", "DELETE").contains( - jsonDynamicResourceDoc.requestVerb - ) - } - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""", - cc = cc.callContext - ) { - ( - jsonDynamicResourceDoc.requestVerb, - jsonDynamicResourceDoc.exampleRequestBody - ) match { - case ( - "GET" | "DELETE", - Some(JString(s)) - ) => // we support the empty string "" here - StringUtils.isBlank(s) - case ( - "GET" | "DELETE", - Some(requestBody) - ) => // we add the guard, we forbid any json objects in GET/DELETE request body. - requestBody == JNothing - case _ => true - } - } - _ = - try { - CompiledObjects( - jsonDynamicResourceDoc.exampleRequestBody, - jsonDynamicResourceDoc.successResponseBody, - jsonDynamicResourceDoc.methodBody - ) - .validateDependency() - } catch { - case e: JsonResponseException => - throw e - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - _ = - try { - CompiledObjects( - jsonDynamicResourceDoc.exampleRequestBody, - jsonDynamicResourceDoc.successResponseBody, - jsonDynamicResourceDoc.methodBody - ) - } catch { - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - - (isExists, callContext) <- NewStyle.function - .isJsonDynamicResourceDocExists( - Some(bankId), - jsonDynamicResourceDoc.requestVerb, - jsonDynamicResourceDoc.requestUrl, - Some(cc) - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", - cc = callContext - ) { - (!isExists) - } - - (dynamicResourceDoc, callContext) <- NewStyle.function - .createJsonDynamicResourceDoc( - Some(bankId), - jsonDynamicResourceDoc, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateBankLevelDynamicResourceDoc, - implementedInApiVersion, - nameOf(updateBankLevelDynamicResourceDoc), - "PUT", - "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Update Bank Level Dynamic Resource Doc", - s"""Update a Bank Level Dynamic Resource Doc. - | - |The connector_method_body is URL-encoded format String - |""", - jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), - jsonDynamicResourceDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canUpdateBankLevelDynamicResourceDoc)) - ) - - lazy val updateBankLevelDynamicResourceDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicResourceDocBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicResourceDoc] - } - - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", - cc = cc.callContext - ) { - Set("POST", "PUT", "GET", "DELETE").contains( - dynamicResourceDocBody.requestVerb - ) - } - - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", - cc = cc.callContext - ) { - ( - dynamicResourceDocBody.requestVerb, - dynamicResourceDocBody.exampleRequestBody - ) match { - case ("GET" | "DELETE", Some(JString(s))) => - StringUtils.isBlank(s) - case ("GET" | "DELETE", Some(requestBody)) => - requestBody == JNothing - case _ => true - } - } - _ = - try { - CompiledObjects( - dynamicResourceDocBody.exampleRequestBody, - dynamicResourceDocBody.successResponseBody, - dynamicResourceDocBody.methodBody - ) - .validateDependency() - } catch { - case e: JsonResponseException => - throw e - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - - _ = - try { - CompiledObjects( - dynamicResourceDocBody.exampleRequestBody, - dynamicResourceDocBody.successResponseBody, - jsonDynamicResourceDoc.methodBody - ) - } catch { - case e: Exception => - val jsonResponse = createErrorJsonResponse( - s"$DynamicCodeCompileFail ${e.getMessage}", - 400, - cc.correlationId - ) - throw JsonResponseException(jsonResponse) - } - - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( - Some(bankId), - dynamicResourceDocId, - cc.callContext - ) - - (dynamicResourceDoc, callContext) <- NewStyle.function - .updateJsonDynamicResourceDoc( - Some(bankId), - dynamicResourceDocBody.copy(dynamicResourceDocId = - Some(dynamicResourceDocId) - ), - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelDynamicResourceDoc, - implementedInApiVersion, - nameOf(deleteBankLevelDynamicResourceDoc), - "DELETE", - "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Delete Bank Level Dynamic Resource Doc", - s"""Delete a Bank Level Dynamic Resource Doc. - |""", - EmptyBody, - BooleanBody(true), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canDeleteBankLevelDynamicResourceDoc)) - ) - - lazy val deleteBankLevelDynamicResourceDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( - Some(bankId), - dynamicResourceDocId, - cc.callContext - ) - (dynamicResourceDoc, callContext) <- NewStyle.function - .deleteJsonDynamicResourceDocById( - Some(bankId), - dynamicResourceDocId, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelDynamicResourceDoc, - implementedInApiVersion, - nameOf(getBankLevelDynamicResourceDoc), - "GET", - "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", - "Get Bank Level Dynamic Resource Doc by Id", - s"""Get a Bank Level Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID. - | - |""", - EmptyBody, - jsonDynamicResourceDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canGetBankLevelDynamicResourceDoc)) - ) - - lazy val getBankLevelDynamicResourceDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicResourceDoc, callContext) <- NewStyle.function - .getJsonDynamicResourceDocById( - Some(bankId), - dynamicResourceDocId, - cc.callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllBankLevelDynamicResourceDocs, - implementedInApiVersion, - nameOf(getAllBankLevelDynamicResourceDocs), - "GET", - "/management/banks/BANK_ID/dynamic-resource-docs", - "Get all Bank Level Dynamic Resource Docs", - s"""Get all Bank Level Dynamic Resource Docs. - | - |""", - EmptyBody, - ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicResourceDoc), - Some(List(canGetAllBankLevelDynamicResourceDocs)) - ) - - lazy val getAllBankLevelDynamicResourceDocs: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicResourceDocs, callContext) <- NewStyle.function - .getJsonDynamicResourceDocs(Some(bankId), cc.callContext) - } yield { - ( - ListResult("dynamic-resource-docs", dynamicResourceDocs), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - buildDynamicEndpointTemplate, - implementedInApiVersion, - nameOf(buildDynamicEndpointTemplate), - "POST", - "/management/dynamic-resource-docs/endpoint-code", - "Create Dynamic Resource Doc endpoint code", - s"""Create a Dynamic Resource Doc endpoint code. - | - |copy the response and past to ${nameOf( - PractiseEndpoint - )}, So you can have the benefits of - |auto compilation and debug - |""", - jsonResourceDocFragment, - jsonCodeTemplateJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicResourceDoc), - None - ) - - lazy val buildDynamicEndpointTemplate: OBPEndpoint = { - case "management" :: "dynamic-resource-docs" :: "endpoint-code" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - resourceDocFragment <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $ResourceDocFragment", - 400, - cc.callContext - ) { - json.extract[ResourceDocFragment] - } - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", - cc = cc.callContext - ) { - Set("POST", "PUT", "GET", "DELETE").contains( - resourceDocFragment.requestVerb - ) - } - - _ <- Helper.booleanToFuture( - failMsg = - s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", - cc = cc.callContext - ) { - ( - resourceDocFragment.requestVerb, - resourceDocFragment.exampleRequestBody - ) match { - case ("GET" | "DELETE", Some(JString(s))) => - StringUtils.isBlank(s) - case ("GET" | "DELETE", Some(requestBody)) => - requestBody == JNothing - case _ => true - } - } - - code = DynamicEndpointCodeGenerator.buildTemplate( - resourceDocFragment - ) - - } yield { - ( - JsonCodeTemplateJson(URLEncoder.encode(code, "UTF-8")), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createDynamicMessageDoc, - implementedInApiVersion, - nameOf(createDynamicMessageDoc), - "POST", - "/management/dynamic-message-docs", - "Create Dynamic Message Doc", - s"""Create a Dynamic Message Doc. - |""", - jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), - jsonDynamicMessageDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canCreateDynamicMessageDoc)) - ) - - lazy val createDynamicMessageDoc: OBPEndpoint = { - case "management" :: "dynamic-message-docs" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicMessageDoc <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicMessageDoc] - } - (dynamicMessageDocExisted, callContext) <- NewStyle.function - .isJsonDynamicMessageDocExists( - None, - dynamicMessageDoc.process, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", - cc = callContext - ) { - (!dynamicMessageDocExisted) - } - connectorMethod = DynamicConnector.createFunction( - dynamicMessageDoc.programmingLang, - dynamicMessageDoc.decodedMethodBody - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.orNull) - (dynamicMessageDoc, callContext) <- NewStyle.function - .createJsonDynamicMessageDoc(None, dynamicMessageDoc, callContext) - } yield { - (dynamicMessageDoc, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createBankLevelDynamicMessageDoc, - implementedInApiVersion, - nameOf(createBankLevelDynamicMessageDoc), - "POST", - "/management/banks/BANK_ID/dynamic-message-docs", - "Create Bank Level Dynamic Message Doc", - s"""Create a Bank Level Dynamic Message Doc. - |""", - jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), - jsonDynamicMessageDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canCreateBankLevelDynamicMessageDoc)) - ) - - lazy val createBankLevelDynamicMessageDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicMessageDoc <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicMessageDoc] - } - (dynamicMessageDocExisted, callContext) <- NewStyle.function - .isJsonDynamicMessageDocExists( - Some(bankId), - dynamicMessageDoc.process, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", - cc = callContext - ) { - (!dynamicMessageDocExisted) - } - connectorMethod = DynamicConnector.createFunction( - dynamicMessageDoc.programmingLang, - dynamicMessageDoc.decodedMethodBody - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.orNull) - (dynamicMessageDoc, callContext) <- NewStyle.function - .createJsonDynamicMessageDoc( - Some(bankId), - dynamicMessageDoc, - callContext - ) - } yield { - (dynamicMessageDoc, HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateDynamicMessageDoc, - implementedInApiVersion, - nameOf(updateDynamicMessageDoc), - "PUT", - "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Update Dynamic Message Doc", - s"""Update a Dynamic Message Doc. - |""", - jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), - jsonDynamicMessageDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canUpdateDynamicMessageDoc)) - ) - - lazy val updateDynamicMessageDoc: OBPEndpoint = { - case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicMessageDocBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicMessageDoc] - } - connectorMethod = DynamicConnector.createFunction( - dynamicMessageDocBody.programmingLang, - dynamicMessageDocBody.decodedMethodBody - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture( - failMsg = errorMsg, - cc = cc.callContext - ) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.orNull) - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( - None, - dynamicMessageDocId, - cc.callContext - ) - (dynamicMessageDoc, callContext) <- NewStyle.function - .updateJsonDynamicMessageDoc( - None, - dynamicMessageDocBody.copy(dynamicMessageDocId = - Some(dynamicMessageDocId) - ), - callContext - ) - } yield { - (dynamicMessageDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getDynamicMessageDoc, - implementedInApiVersion, - nameOf(getDynamicMessageDoc), - "GET", - "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Get Dynamic Message Doc", - s"""Get a Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID. - | - |""", - EmptyBody, - jsonDynamicMessageDoc, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canGetDynamicMessageDoc)) - ) - - lazy val getDynamicMessageDoc: OBPEndpoint = { - case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicMessageDoc, callContext) <- NewStyle.function - .getJsonDynamicMessageDocById( - None, - dynamicMessageDocId, - cc.callContext - ) - } yield { - (dynamicMessageDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllDynamicMessageDocs, - implementedInApiVersion, - nameOf(getAllDynamicMessageDocs), - "GET", - "/management/dynamic-message-docs", - "Get all Dynamic Message Docs", - s"""Get all Dynamic Message Docs. - | - |""", - EmptyBody, - ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canGetAllDynamicMessageDocs)) - ) - - lazy val getAllDynamicMessageDocs: OBPEndpoint = { - case "management" :: "dynamic-message-docs" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicMessageDocs, callContext) <- NewStyle.function - .getJsonDynamicMessageDocs(None, cc.callContext) - } yield { - ( - ListResult("dynamic-message-docs", dynamicMessageDocs), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteDynamicMessageDoc, - implementedInApiVersion, - nameOf(deleteDynamicMessageDoc), - "DELETE", - "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Delete Dynamic Message Doc", - s"""Delete a Dynamic Message Doc. - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canDeleteDynamicMessageDoc)) - ) - - lazy val deleteDynamicMessageDoc: OBPEndpoint = { - case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( - None, - dynamicMessageDocId, - cc.callContext - ) - (dynamicResourceDoc, callContext) <- NewStyle.function - .deleteJsonDynamicMessageDocById( - None, - dynamicMessageDocId, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateBankLevelDynamicMessageDoc, - implementedInApiVersion, - nameOf(updateBankLevelDynamicMessageDoc), - "PUT", - "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Update Bank Level Dynamic Message Doc", - s"""Update a Bank Level Dynamic Message Doc. - |""", - jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), - jsonDynamicMessageDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canUpdateDynamicMessageDoc)) - ) - - lazy val updateBankLevelDynamicMessageDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - dynamicMessageDocBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", - 400, - cc.callContext - ) { - json.extract[JsonDynamicMessageDoc] - } - connectorMethod = DynamicConnector.createFunction( - dynamicMessageDocBody.programmingLang, - dynamicMessageDocBody.decodedMethodBody - ) - errorMsg = - if (connectorMethod.isEmpty) - s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" - else "" - _ <- Helper.booleanToFuture( - failMsg = errorMsg, - cc = cc.callContext - ) { - connectorMethod.isDefined - } - _ = Validation.validateDependency(connectorMethod.orNull) - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( - Some(bankId), - dynamicMessageDocId, - cc.callContext - ) - (dynamicMessageDoc, callContext) <- NewStyle.function - .updateJsonDynamicMessageDoc( - Some(bankId), - dynamicMessageDocBody.copy(dynamicMessageDocId = - Some(dynamicMessageDocId) - ), - callContext - ) - } yield { - (dynamicMessageDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelDynamicMessageDoc, - implementedInApiVersion, - nameOf(getBankLevelDynamicMessageDoc), - "GET", - "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Get Bank Level Dynamic Message Doc", - s"""Get a Bank Level Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID. - | - |""", - EmptyBody, - jsonDynamicMessageDoc, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canGetBankLevelDynamicMessageDoc)) - ) - - lazy val getBankLevelDynamicMessageDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicMessageDoc, callContext) <- NewStyle.function - .getJsonDynamicMessageDocById( - None, - dynamicMessageDocId, - cc.callContext - ) - } yield { - (dynamicMessageDoc, HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAllBankLevelDynamicMessageDocs, - implementedInApiVersion, - nameOf(getAllBankLevelDynamicMessageDocs), - "GET", - "/management/banks/BANK_ID/dynamic-message-docs", - "Get all Bank Level Dynamic Message Docs", - s"""Get all Bank Level Dynamic Message Docs. - | - |""", - EmptyBody, - ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canGetAllDynamicMessageDocs)) - ) - - lazy val getAllBankLevelDynamicMessageDocs: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (dynamicMessageDocs, callContext) <- NewStyle.function - .getJsonDynamicMessageDocs(Some(bankId), cc.callContext) - } yield { - ( - ListResult("dynamic-message-docs", dynamicMessageDocs), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelDynamicMessageDoc, - implementedInApiVersion, - nameOf(deleteBankLevelDynamicMessageDoc), - "DELETE", - "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", - "Delete Bank Level Dynamic Message Doc", - s"""Delete a Bank Level Dynamic Message Doc. - |""", - EmptyBody, - BooleanBody(true), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagDynamicMessageDoc), - Some(List(canDeleteBankLevelDynamicMessageDoc)) - ) - - lazy val deleteBankLevelDynamicMessageDoc: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( - Some(bankId), - dynamicMessageDocId, - cc.callContext - ) - (dynamicResourceDoc, callContext) <- NewStyle.function - .deleteJsonDynamicMessageDocById( - Some(bankId), - dynamicMessageDocId, - callContext - ) - } yield { - (dynamicResourceDoc, HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createEndpointMapping, - implementedInApiVersion, - nameOf(createEndpointMapping), - "POST", - "/management/endpoint-mappings", - "Create Endpoint Mapping", - s"""Create an Endpoint Mapping. - | - |Note: at moment only support the dynamic endpoints - |""", - endpointMappingRequestBodyExample, - endpointMappingResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canCreateEndpointMapping)) - ) - - lazy val createEndpointMapping: OBPEndpoint = { - case "management" :: "endpoint-mappings" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - createEndpointMappingMethod(None, json, cc) - } - } - - private def createEndpointMappingMethod( - bankId: Option[String], - json: JValue, - cc: CallContext - ) = { - for { - endpointMapping <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}", - 400, - cc.callContext - ) { - json.extract[EndpointMappingCommons].copy(bankId = bankId) - } - (endpointMapping, callContext) <- NewStyle.function - .createOrUpdateEndpointMapping( - bankId, - endpointMapping.copy( - endpointMappingId = None, - bankId = bankId - ), // create need to make sure, endpointMappingId is None, and bankId must be from URL. - cc.callContext - ) - } yield { - val commonsData: EndpointMappingCommons = endpointMapping - (commonsData.toJson, HttpCode.`201`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - updateEndpointMapping, - implementedInApiVersion, - nameOf(updateEndpointMapping), - "PUT", - "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Update Endpoint Mapping", - s"""Update an Endpoint Mapping. - |""", - endpointMappingRequestBodyExample, - endpointMappingResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canUpdateEndpointMapping)) - ) - - lazy val updateEndpointMapping: OBPEndpoint = { - case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateEndpointMappingMethod(None, endpointMappingId, json, cc) - } - } - - private def updateEndpointMappingMethod( - bankId: Option[String], - endpointMappingId: String, - json: JValue, - cc: CallContext - ) = { - for { - endpointMappingBody <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}", - 400, - cc.callContext - ) { - json.extract[EndpointMappingCommons].copy(bankId = bankId) - } - (endpointMapping, callContext) <- NewStyle.function - .getEndpointMappingById(bankId, endpointMappingId, cc.callContext) - _ <- Helper.booleanToFuture( - s"$InvalidJsonFormat operation_id has to be the same in the URL (${endpointMapping.operationId}) and Body (${endpointMappingBody.operationId}). ", - 400, - cc.callContext - ) { - endpointMapping.operationId == endpointMappingBody.operationId - } - (endpointMapping, callContext) <- NewStyle.function - .createOrUpdateEndpointMapping( - bankId, - endpointMappingBody.copy( - endpointMappingId = Some(endpointMappingId), - bankId = bankId - ), // Update must set the endpointId and BankId must be from URL - callContext - ) - } yield { - val commonsData: EndpointMappingCommons = endpointMapping - (commonsData.toJson, HttpCode.`201`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - getEndpointMapping, - implementedInApiVersion, - nameOf(getEndpointMapping), - "GET", - "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Get Endpoint Mapping by Id", - s"""Get an Endpoint Mapping by ENDPOINT_MAPPING_ID. - | - |""", - EmptyBody, - endpointMappingResponseBodyExample, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canGetEndpointMapping)) - ) - - lazy val getEndpointMapping: OBPEndpoint = { - case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getEndpointMappingMethod(None, endpointMappingId, cc) - } - } - - private def getEndpointMappingMethod( - bankId: Option[String], - endpointMappingId: String, - cc: CallContext - ) = { - for { - (endpointMapping, callContext) <- NewStyle.function - .getEndpointMappingById(bankId, endpointMappingId, cc.callContext) - } yield { - val commonsData: EndpointMappingCommons = endpointMapping - (commonsData.toJson, HttpCode.`201`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - getAllEndpointMappings, - implementedInApiVersion, - nameOf(getAllEndpointMappings), - "GET", - "/management/endpoint-mappings", - "Get all Endpoint Mappings", - s"""Get all Endpoint Mappings. - | - |""", - EmptyBody, - ListResult( - "endpoint-mappings", - endpointMappingResponseBodyExample :: Nil - ), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canGetAllEndpointMappings)) - ) - - lazy val getAllEndpointMappings: OBPEndpoint = { - case "management" :: "endpoint-mappings" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - getEndpointMappingsMethod(None, cc) - } - } - - private def getEndpointMappingsMethod( - bankId: Option[String], - cc: CallContext - ) = { - for { - (endpointMappings, callContext) <- NewStyle.function - .getEndpointMappings(bankId, cc.callContext) - } yield { - val listCommons: List[EndpointMappingCommons] = endpointMappings - ( - ListResult("endpoint-mappings", listCommons.map(_.toJson)), - HttpCode.`200`(callContext) - ) - } - } - - staticResourceDocs += ResourceDoc( - deleteEndpointMapping, - implementedInApiVersion, - nameOf(deleteEndpointMapping), - "DELETE", - "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Delete Endpoint Mapping", - s"""Delete a Endpoint Mapping. - |""", - EmptyBody, - BooleanBody(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canDeleteEndpointMapping)) - ) - - lazy val deleteEndpointMapping: OBPEndpoint = { - case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteEndpointMappingMethod(None, endpointMappingId, cc) - } - } - - private def deleteEndpointMappingMethod( - bankId: Option[String], - endpointMappingId: String, - cc: CallContext - ) = { - for { - (deleted, callContext) <- NewStyle.function.deleteEndpointMapping( - bankId, - endpointMappingId, - cc.callContext - ) - } yield { - (deleted, HttpCode.`200`(callContext)) - } - } - - staticResourceDocs += ResourceDoc( - createBankLevelEndpointMapping, - implementedInApiVersion, - nameOf(createBankLevelEndpointMapping), - "POST", - "/management/banks/BANK_ID/endpoint-mappings", - "Create Bank Level Endpoint Mapping", - s"""Create an Bank Level Endpoint Mapping. - | - |Note: at moment only support the dynamic endpoints - |""", - endpointMappingRequestBodyExample, - endpointMappingResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canCreateBankLevelEndpointMapping, canCreateEndpointMapping)) - ) - - lazy val createBankLevelEndpointMapping: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - createEndpointMappingMethod(Some(bankId), json, cc) - } - } - - staticResourceDocs += ResourceDoc( - updateBankLevelEndpointMapping, - implementedInApiVersion, - nameOf(updateBankLevelEndpointMapping), - "PUT", - "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Update Bank Level Endpoint Mapping", - s"""Update an Bank Level Endpoint Mapping. - |""", - endpointMappingRequestBodyExample, - endpointMappingResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canUpdateBankLevelEndpointMapping, canUpdateEndpointMapping)) - ) - - lazy val updateBankLevelEndpointMapping: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - updateEndpointMappingMethod(Some(bankId), endpointMappingId, json, cc) - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelEndpointMapping, - implementedInApiVersion, - nameOf(getBankLevelEndpointMapping), - "GET", - "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Get Bank Level Endpoint Mapping", - s"""Get an Bank Level Endpoint Mapping by ENDPOINT_MAPPING_ID. - | - |""", - EmptyBody, - endpointMappingResponseBodyExample, - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canGetBankLevelEndpointMapping, canGetEndpointMapping)) - ) - - lazy val getBankLevelEndpointMapping: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getEndpointMappingMethod(Some(bankId), endpointMappingId, cc) - } - } - - staticResourceDocs += ResourceDoc( - getAllBankLevelEndpointMappings, - implementedInApiVersion, - nameOf(getAllBankLevelEndpointMappings), - "GET", - "/management/banks/BANK_ID/endpoint-mappings", - "Get all Bank Level Endpoint Mappings", - s"""Get all Bank Level Endpoint Mappings. - | - |""", - EmptyBody, - ListResult( - "endpoint-mappings", - endpointMappingResponseBodyExample :: Nil - ), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canGetAllBankLevelEndpointMappings, canGetAllEndpointMappings)) - ) - - lazy val getAllBankLevelEndpointMappings: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - getEndpointMappingsMethod(Some(bankId), cc) - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelEndpointMapping, - implementedInApiVersion, - nameOf(deleteBankLevelEndpointMapping), - "DELETE", - "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", - "Delete Bank Level Endpoint Mapping", - s"""Delete a Bank Level Endpoint Mapping. - |""", - EmptyBody, - BooleanBody(true), - List( - $BankNotFound, - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagEndpointMapping), - Some(List(canDeleteBankLevelEndpointMapping, canDeleteEndpointMapping)) - ) - - lazy val deleteBankLevelEndpointMapping: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - deleteEndpointMappingMethod(Some(bankId), endpointMappingId, cc) - } - } - - staticResourceDocs += ResourceDoc( - updateAtmSupportedCurrencies, - implementedInApiVersion, - nameOf(updateAtmSupportedCurrencies), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/supported-currencies", - "Update ATM Supported Currencies", - s"""Update ATM Supported Currencies. - |""", - supportedCurrenciesJson, - atmSupportedCurrenciesJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmSupportedCurrencies: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "supported-currencies" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - supportedCurrencies <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedCurrenciesJson]}", - 400, - cc.callContext - ) { - json.extract[SupportedCurrenciesJson].supported_currencies - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function.updateAtmSupportedCurrencies( - bankId, - atmId, - supportedCurrencies, - cc.callContext - ) - } yield { - ( - AtmSupportedCurrenciesJson( - atm.atmId.value, - atm.supportedCurrencies.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtmSupportedLanguages, - implementedInApiVersion, - nameOf(updateAtmSupportedLanguages), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/supported-languages", - "Update ATM Supported Languages", - s"""Update ATM Supported Languages. - |""", - supportedLanguagesJson, - atmSupportedLanguagesJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmSupportedLanguages: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "supported-languages" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - supportedLanguages <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedLanguagesJson]}", - 400, - cc.callContext - ) { - json.extract[SupportedLanguagesJson].supported_languages - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function.updateAtmSupportedLanguages( - bankId, - atmId, - supportedLanguages, - cc.callContext - ) - } yield { - ( - AtmSupportedLanguagesJson( - atm.atmId.value, - atm.supportedLanguages.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtmAccessibilityFeatures, - implementedInApiVersion, - nameOf(updateAtmAccessibilityFeatures), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/accessibility-features", - "Update ATM Accessibility Features", - s"""Update ATM Accessibility Features. - |""", - accessibilityFeaturesJson, - atmAccessibilityFeaturesJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmAccessibilityFeatures: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "accessibility-features" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - accessibilityFeatures <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AccessibilityFeaturesJson]}", - 400, - cc.callContext - ) { - json.extract[AccessibilityFeaturesJson].accessibility_features - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function - .updateAtmAccessibilityFeatures( - bankId, - atmId, - accessibilityFeatures, - cc.callContext - ) - } yield { - ( - AtmAccessibilityFeaturesJson( - atm.atmId.value, - atm.accessibilityFeatures.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtmServices, - implementedInApiVersion, - nameOf(updateAtmServices), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/services", - "Update ATM Services", - s"""Update ATM Services. - |""", - atmServicesJson, - atmServicesResponseJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmServices: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "services" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - services <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AtmServicesJsonV400]}", - 400, - cc.callContext - ) { - json.extract[AtmServicesJsonV400].services - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function.updateAtmServices( - bankId, - atmId, - services, - cc.callContext - ) - } yield { - ( - AtmServicesResponseJsonV400( - atm.atmId.value, - atm.services.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtmNotes, - implementedInApiVersion, - nameOf(updateAtmNotes), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/notes", - "Update ATM Notes", - s"""Update ATM Notes. - |""", - atmNotesJson, - atmNotesResponseJson, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmNotes: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "notes" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - notes <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AtmNotesJsonV400]}", - 400, - cc.callContext - ) { - json.extract[AtmNotesJsonV400].notes - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function.updateAtmNotes( - bankId, - atmId, - notes, - cc.callContext - ) - } yield { - ( - AtmServicesResponseJsonV400( - atm.atmId.value, - atm.notes.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtmLocationCategories, - implementedInApiVersion, - nameOf(updateAtmLocationCategories), - "PUT", - "/banks/BANK_ID/atms/ATM_ID/location-categories", - "Update ATM Location Categories", - s"""Update ATM Location Categories. - |""", - atmLocationCategoriesJsonV400, - atmLocationCategoriesResponseJsonV400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - - lazy val updateAtmLocationCategories: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: "location-categories" :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - locationCategories <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AtmLocationCategoriesJsonV400]}", - 400, - cc.callContext - ) { - json.extract[AtmLocationCategoriesJsonV400].location_categories - } - (_, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (atm, callContext) <- NewStyle.function.updateAtmLocationCategories( - bankId, - atmId, - locationCategories, - cc.callContext - ) - } yield { - ( - AtmLocationCategoriesResponseJsonV400( - atm.atmId.value, - atm.locationCategories.getOrElse(Nil) - ), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createAtm, - implementedInApiVersion, - nameOf(createAtm), - "POST", - "/banks/BANK_ID/atms", - "Create ATM", - s"""Create ATM.""", - atmJsonV400, - atmJsonV400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM), - Some(List(canCreateAtm, canCreateAtmAtAnyBank)) - ) - lazy val createAtm: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - atmJsonV400 <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}", - 400, - cc.callContext - ) { - val atm = json.extract[AtmJsonV400] - // Make sure the Create contains proper ATM ID - atm.id.get - atm - } - _ <- Helper.booleanToFuture( - s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", - 400, - cc.callContext - ) { atmJsonV400.bank_id == bankId.value } - atm <- NewStyle.function.tryons( - ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm", - 400, - cc.callContext - ) { - JSONFactory400.transformToAtmFromV400(atmJsonV400) - } - (atm, callContext) <- NewStyle.function.createOrUpdateAtm( - atm, - cc.callContext - ) - } yield { - (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - updateAtm, - implementedInApiVersion, - nameOf(updateAtm), - "PUT", - "/banks/BANK_ID/atms/ATM_ID", - "UPDATE ATM", - s"""Update ATM.""", - atmJsonV400.copy(id = None), - atmJsonV400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM), - Some(List(canUpdateAtm, canUpdateAtmAtAnyBank)) - ) - lazy val updateAtm: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (atm, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - atmJsonV400 <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}", - 400, - cc.callContext - ) { - json.extract[AtmJsonV400] - } - _ <- Helper.booleanToFuture( - s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", - 400, - cc.callContext - ) { atmJsonV400.bank_id == bankId.value } - atm <- NewStyle.function.tryons( - ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm", - 400, - cc.callContext - ) { - JSONFactory400.transformToAtmFromV400( - atmJsonV400.copy(id = Some(atmId.value)) - ) - } - (atm, callContext) <- NewStyle.function.createOrUpdateAtm( - atm, - cc.callContext - ) - } yield { - (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteAtm, - implementedInApiVersion, - nameOf(deleteAtm), - "DELETE", - "/banks/BANK_ID/atms/ATM_ID", - "Delete ATM", - s"""Delete ATM.""", - EmptyBody, - EmptyBody, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagATM), - Some(List(canDeleteAtmAtAnyBank, canDeleteAtm)) - ) - lazy val deleteAtm: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: Nil JsonDelete _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (atm, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - cc.callContext - ) - (deleted, callContext) <- NewStyle.function.deleteAtm( - atm, - callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAtms, - implementedInApiVersion, - nameOf(getAtms), - "GET", - "/banks/BANK_ID/atms", - "Get Bank ATMS", - s"""Returns information about ATMs for a single bank specified by BANK_ID including: - | - |* Address - |* Geo Location - |* License the data under this endpoint is released under - | - |Pagination: - | - |By default, 100 records are returned. - | - |You can use the url query parameters *limit* and *offset* for pagination - | - |${userAuthenticationMessage(!getAtmsIsPublic)}""".stripMargin, - EmptyBody, - atmsJsonV400, - List( - $BankNotFound, - UnknownError - ), - List(apiTagATM) - ) - lazy val getAtms: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - val limit = ObpS.param("limit") - val offset = ObpS.param("offset") - for { - (_, callContext) <- getAtmsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - _ <- Helper.booleanToFuture( - failMsg = s"${InvalidNumber} limit:${limit.getOrElse("")}", - cc = callContext - ) { - limit match { - case Full(i) => i.toList.forall(c => Character.isDigit(c) == true) - case _ => true - } - } - _ <- Helper.booleanToFuture( - failMsg = maximumLimitExceeded, - cc = callContext - ) { - limit match { - case Full(i) if i.toInt > 10000 => false - case _ => true - } - } - (atms, callContext) <- NewStyle.function.getAtmsByBankId( - bankId, - offset, - limit, - cc.callContext - ) - } yield { - (JSONFactory400.createAtmsJsonV400(atms), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getAtm, - implementedInApiVersion, - nameOf(getAtm), - "GET", - "/banks/BANK_ID/atms/ATM_ID", - "Get Bank ATM", - s"""Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including: - | - |* Address - |* Geo Location - |* License the data under this endpoint is released under - |${userAuthenticationMessage(!getAtmsIsPublic)} - |""".stripMargin, - EmptyBody, - atmJsonV400, - List( - $AuthenticatedUserIsRequired, - InvalidJsonFormat, - UnknownError - ), - List(apiTagATM) - ) - lazy val getAtm: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "atms" :: AtmId( - atmId - ) :: Nil JsonGet req => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getAtmsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (atm, callContext) <- NewStyle.function.getAtm( - bankId, - atmId, - callContext - ) - } yield { - (JSONFactory400.createAtmJsonV400(atm), HttpCode.`200`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createSystemLevelEndpointTag, - implementedInApiVersion, - nameOf(createSystemLevelEndpointTag), - "POST", - "/management/endpoints/OPERATION_ID/tags", - "Create System Level Endpoint Tag", - s"""Create System Level Endpoint Tag - | - |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds - | - |""".stripMargin, - endpointTagJson400, - bankLevelEndpointTagResponseJson400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApi), - Some(List(canCreateSystemLevelEndpointTag)) - ) - lazy val createSystemLevelEndpointTag: OBPEndpoint = { - case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - endpointTag <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", - 400, - cc.callContext - ) { - json.extract[EndpointTagJson400] - } - (endpointTagExisted, callContext) <- NewStyle.function - .checkSystemLevelEndpointTagExists( - operationId, - endpointTag.tag_name, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})", - cc = callContext - ) { - (!endpointTagExisted) - } - (endpointTag, callContext) <- NewStyle.function - .createSystemLevelEndpointTag( - operationId, - endpointTag.tag_name, - cc.callContext - ) - } yield { - ( - SystemLevelEndpointTagResponseJson400( - endpointTag.endpointTagId.getOrElse(""), - endpointTag.operationId, - endpointTag.tagName - ), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateSystemLevelEndpointTag, - implementedInApiVersion, - nameOf(updateSystemLevelEndpointTag), - "PUT", - "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", - "Update System Level Endpoint Tag", - s"""Update System Level Endpoint Tag, you can only update the tag_name here, operation_id can not be updated. - | - |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds - | - |""".stripMargin, - endpointTagJson400, - bankLevelEndpointTagResponseJson400, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - EndpointTagNotFoundByEndpointTagId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApi), - Some(List(canUpdateSystemLevelEndpointTag)) - ) - lazy val updateSystemLevelEndpointTag: OBPEndpoint = { - case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - endpointTag <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", - 400, - cc.callContext - ) { - json.extract[EndpointTagJson400] - } - (_, callContext) <- NewStyle.function.getEndpointTag( - endpointTagId, - cc.callContext - ) - (endpointTagExisted, callContext) <- NewStyle.function - .checkSystemLevelEndpointTagExists( - operationId, - endpointTag.tag_name, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name", - cc = callContext - ) { - (!endpointTagExisted) - } - (endpointTagT, callContext) <- NewStyle.function - .updateSystemLevelEndpointTag( - endpointTagId, - operationId, - endpointTag.tag_name, - cc.callContext - ) - } yield { - ( - SystemLevelEndpointTagResponseJson400( - endpointTagT.endpointTagId.getOrElse(""), - endpointTagT.operationId, - endpointTagT.tagName - ), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getSystemLevelEndpointTags, - implementedInApiVersion, - nameOf(getSystemLevelEndpointTags), - "GET", - "/management/endpoints/OPERATION_ID/tags", - "Get System Level Endpoint Tags", - s"""Get System Level Endpoint Tags.""", - EmptyBody, - bankLevelEndpointTagResponseJson400 :: Nil, - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagApi), - Some(List(canGetSystemLevelEndpointTag)) - ) - lazy val getSystemLevelEndpointTags: OBPEndpoint = { - case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (endpointTags, callContext) <- NewStyle.function - .getSystemLevelEndpointTags(operationId, cc.callContext) - } yield { - ( - endpointTags.map(endpointTagT => - SystemLevelEndpointTagResponseJson400( - endpointTagT.endpointTagId.getOrElse(""), - endpointTagT.operationId, - endpointTagT.tagName - ) - ), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteSystemLevelEndpointTag, - implementedInApiVersion, - nameOf(deleteSystemLevelEndpointTag), - "DELETE", - "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", - "Delete System Level Endpoint Tag", - s"""Delete System Level Endpoint Tag.""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - UserHasMissingRoles, - UnknownError - ), - List(apiTagApi), - Some(List(canDeleteSystemLevelEndpointTag)) - ) - lazy val deleteSystemLevelEndpointTag: OBPEndpoint = { - case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getEndpointTag( - endpointTagId, - cc.callContext - ) - - (deleted, callContext) <- NewStyle.function.deleteEndpointTag( - endpointTagId, - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - createBankLevelEndpointTag, - implementedInApiVersion, - nameOf(createBankLevelEndpointTag), - "POST", - "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags", - "Create Bank Level Endpoint Tag", - s"""Create Bank Level Endpoint Tag - | - |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds - | - | - |""".stripMargin, - endpointTagJson400, - bankLevelEndpointTagResponseJson400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApi), - Some(List(canCreateBankLevelEndpointTag)) - ) - lazy val createBankLevelEndpointTag: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - endpointTag <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", - 400, - cc.callContext - ) { - json.extract[EndpointTagJson400] - } - (endpointTagExisted, callContext) <- NewStyle.function - .checkBankLevelEndpointTagExists( - bankId, - operationId, - endpointTag.tag_name, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})", - cc = callContext - ) { - (!endpointTagExisted) - } - (endpointTagT, callContext) <- NewStyle.function - .createBankLevelEndpointTag( - bankId, - operationId, - endpointTag.tag_name, - cc.callContext - ) - } yield { - ( - BankLevelEndpointTagResponseJson400( - endpointTagT.bankId.getOrElse(""), - endpointTagT.endpointTagId.getOrElse(""), - endpointTagT.operationId, - endpointTagT.tagName - ), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - updateBankLevelEndpointTag, - implementedInApiVersion, - nameOf(updateBankLevelEndpointTag), - "PUT", - "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", - "Update Bank Level Endpoint Tag", - s"""Update Endpoint Tag, you can only update the tag_name here, operation_id can not be updated. - | - |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds - | - |""".stripMargin, - endpointTagJson400, - bankLevelEndpointTagResponseJson400, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - EndpointTagNotFoundByEndpointTagId, - InvalidJsonFormat, - UnknownError - ), - List(apiTagApi), - Some(List(canUpdateBankLevelEndpointTag)) - ) - lazy val updateBankLevelEndpointTag: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - endpointTag <- NewStyle.function.tryons( - s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", - 400, - cc.callContext - ) { - json.extract[EndpointTagJson400] - } - (_, callContext) <- NewStyle.function.getEndpointTag( - endpointTagId, - cc.callContext - ) - (endpointTagExisted, callContext) <- NewStyle.function - .checkBankLevelEndpointTagExists( - bankId, - operationId, - endpointTag.tag_name, - cc.callContext - ) - _ <- Helper.booleanToFuture( - failMsg = - s"$EndpointTagAlreadyExists BANK_ID($bankId), OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name", - cc = callContext - ) { - (!endpointTagExisted) - } - (endpointTagT, callContext) <- NewStyle.function - .updateBankLevelEndpointTag( - bankId, - endpointTagId, - operationId, - endpointTag.tag_name, - cc.callContext - ) - } yield { - ( - BankLevelEndpointTagResponseJson400( - endpointTagT.bankId.getOrElse(""), - endpointTagT.endpointTagId.getOrElse(""), - endpointTagT.operationId, - endpointTagT.tagName - ), - HttpCode.`201`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getBankLevelEndpointTags, - implementedInApiVersion, - nameOf(getBankLevelEndpointTags), - "GET", - "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags", - "Get Bank Level Endpoint Tags", - s"""Get Bank Level Endpoint Tags.""", - EmptyBody, - bankLevelEndpointTagResponseJson400 :: Nil, - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagApi), - Some(List(canGetBankLevelEndpointTag)) - ) - lazy val getBankLevelEndpointTags: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (endpointTags, callContext) <- NewStyle.function - .getBankLevelEndpointTags(bankId, operationId, cc.callContext) - } yield { - ( - endpointTags.map(endpointTagT => - BankLevelEndpointTagResponseJson400( - endpointTagT.bankId.getOrElse(""), - endpointTagT.endpointTagId.getOrElse(""), - endpointTagT.operationId, - endpointTagT.tagName - ) - ), - HttpCode.`200`(cc.callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - deleteBankLevelEndpointTag, - implementedInApiVersion, - nameOf(deleteBankLevelEndpointTag), - "DELETE", - "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", - "Delete Bank Level Endpoint Tag", - s"""Delete Bank Level Endpoint Tag.""", - EmptyBody, - Full(true), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagApi), - Some(List(canDeleteBankLevelEndpointTag)) - ) - lazy val deleteBankLevelEndpointTag: OBPEndpoint = { - case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- NewStyle.function.getEndpointTag( - endpointTagId, - cc.callContext - ) - - (deleted, callContext) <- NewStyle.function.deleteEndpointTag( - endpointTagId, - cc.callContext - ) - } yield { - (Full(deleted), HttpCode.`204`(callContext)) - } - } - } - - staticResourceDocs += ResourceDoc( - getMySpaces, - implementedInApiVersion, - nameOf(getMySpaces), - "GET", - "/my/spaces", - "Get My Spaces", - s"""Get My Spaces.""", - EmptyBody, - mySpaces, - List( - $AuthenticatedUserIsRequired, - UnknownError - ), - List(apiTagUser) - ) - lazy val getMySpaces: OBPEndpoint = { - case "my" :: "spaces" :: Nil JsonGet _ => { cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - entitlements <- NewStyle.function.getEntitlementsByUserId( - u.userId, - callContext - ) - } yield { - ( - MySpaces( - entitlements - .filter( - _.roleName == canReadDynamicResourceDocsAtOneBank.toString() - ) - .map(entitlement => entitlement.bankId) - ), - HttpCode.`200`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getProducts, - implementedInApiVersion, - "getProducts", - "GET", - "/banks/BANK_ID/products", - "Get Products", - s"""Returns information about the financial products offered by a bank specified by BANK_ID including: - | - |* Name - |* Code - |* Parent Product Code - |* More info URL - |* Terms And Conditions URL - |* Description - |* Terms and Conditions - |* License the data under this endpoint is released under - | - |The combination of bank_id and product_code is unique. - | - |Can filter with attributes name and values. - |URL params example: /banks/some-bank-id/products?&limit=50&offset=1 - | - |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, - EmptyBody, - productsJsonV400, - List( - AuthenticatedUserIsRequired, - BankNotFound, - UnknownError - ), - List(apiTagProduct) - ) - lazy val getProducts: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (_, callContext) <- NewStyle.function.getBank(bankId, callContext) - params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2)) - (products, callContext) <- NewStyle.function.getProducts( - bankId, - params, - callContext - ) - } yield { - ( - JSONFactory400.createProductsJson(products), - HttpCode.`200`(callContext) - ) - } - } - } - } - - 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 - | - | - |${userAuthenticationMessage(true)} - | - | - |""", - putProductJsonV400, - productJsonV400.copy(attributes = None, fees = None), - List( - $AuthenticatedUserIsRequired, - $BankNotFound, - UserHasMissingRoles, - UnknownError - ), - List(apiTagProduct), - Some(List(canCreateProduct, canCreateProductAtAnyBank)) - ) - lazy val createProduct: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: ProductCode( - productCode - ) :: Nil JsonPut json -> _ => { cc => - implicit val ec = EndpointContext(Some(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[PutProductJsonV400] - } - (parentProduct, callContext) <- - product.parent_product_code.trim.nonEmpty match { - case false => - Future((Empty, callContext)) - case true => - NewStyle.function - .getProduct( - bankId, - ProductCode(product.parent_product_code), - callContext - ) - .map(product => (Full(product._1), product._2)) - } - (success, callContext) <- NewStyle.function.createOrUpdateProduct( - bankId = bankId.value, - code = productCode.value, - parentProductCode = parentProduct.map(_.code.value).toOption, - name = product.name, - category = null, - family = null, - superFamily = null, - moreInfoUrl = product.more_info_url, - termsAndConditionsUrl = product.terms_and_conditions_url, - details = null, - description = product.description, - metaLicenceId = product.meta.license.id, - metaLicenceName = product.meta.license.name, - callContext - ) - } yield { - ( - JSONFactory400.createProductJson(success), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - getProduct, - implementedInApiVersion, - nameOf(getProduct), - "GET", - "/banks/BANK_ID/products/PRODUCT_CODE", - "Get Bank Product", - s"""Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including: - | - |* Name - |* Code - |* Parent Product Code - |* More info URL - |* Description - |* Terms and Conditions - |* Description - |* Meta - |* Attributes - |* Fees - | - |The combination of bank_id and product_code is unique. - | - |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, - EmptyBody, - productJsonV400, - List( - AuthenticatedUserIsRequired, - $BankNotFound, - ProductNotFoundByProductCode, - UnknownError - ), - List(apiTagProduct) - ) - - lazy val getProduct: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "products" :: ProductCode( - productCode - ) :: Nil JsonGet _ => { cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (_, callContext) <- getProductsIsPublic match { - case false => authenticatedAccess(cc) - case true => anonymousAccess(cc) - } - (product, callContext) <- NewStyle.function.getProduct( - bankId, - productCode, - callContext - ) - (productAttributes, callContext) <- NewStyle.function - .getProductAttributesByBankAndCode( - bankId, - productCode, - callContext - ) - - (productFees, callContext) <- NewStyle.function - .getProductFeesFromProvider(bankId, productCode, callContext) - - } yield { - ( - JSONFactory400.createProductJson( - product, - productAttributes, - productFees - ), - HttpCode.`200`(callContext) - ) - } - } - } - } - - staticResourceDocs += ResourceDoc( - createCustomerMessage, - implementedInApiVersion, - nameOf(createCustomerMessage), - "POST", - "/banks/BANK_ID/customers/CUSTOMER_ID/messages", - "Create Customer Message", - s""" - |Create a message for the customer specified by CUSTOMER_ID - |${userAuthenticationMessage(true)} - | - |""".stripMargin, - createMessageJsonV400, - successMessage, - List( - AuthenticatedUserIsRequired, - $BankNotFound - ), - List(apiTagMessage, apiTagCustomer, apiTagPerson), - Some(List(canCreateCustomerMessage)) - ) - - lazy val createCustomerMessage: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "customers" :: customerId :: "messages" :: Nil JsonPost json -> _ => { - cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - failMsg = - s"$InvalidJsonFormat The Json body should be the $CreateMessageJsonV400 " - postedData <- NewStyle.function.tryons( - failMsg, - 400, - callContext - ) { - json.extract[CreateMessageJsonV400] - } - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, callContext) - (_, callContext) <- NewStyle.function.createCustomerMessage( - customer, - bankId, - postedData.transport, - postedData.message, - postedData.from_department, - postedData.from_person, - callContext - ) - } yield { - (successMessage, HttpCode.`201`(callContext)) - } - } - } - } - - staticResourceDocs += ResourceDoc( - getCustomerMessages, - implementedInApiVersion, - nameOf(getCustomerMessages), - "GET", - "/banks/BANK_ID/customers/CUSTOMER_ID/messages", - "Get Customer Messages for a Customer", - s"""Get messages for the customer specified by CUSTOMER_ID - ${userAuthenticationMessage(true)} - """, - EmptyBody, - customerMessagesJsonV400, - List(AuthenticatedUserIsRequired, $BankNotFound, UnknownError), - List(apiTagMessage, apiTagCustomer), - Some(List(canGetCustomerMessages)) - ) - - lazy val getCustomerMessages: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "customers" :: customerId :: "messages" :: Nil JsonGet _ => { - cc => - { - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- SS.user - (customer, callContext) <- NewStyle.function - .getCustomerByCustomerId(customerId, callContext) - (messages, callContext) <- NewStyle.function.getCustomerMessages( - customer, - bankId, - callContext - ) - } yield { - ( - JSONFactory400.createCustomerMessagesJson(messages), - HttpCode.`200`(callContext) - ) - } - } - } - } - - val generalWebHookInfo = s""" - |Webhooks are used to call external web services when certain events happen. - | - |For instance, a webhook can be used to notify an external service if a transaction is created on an account. - | - |""" - - val accountNotificationWebhookInfo = s""" - |When an account notification webhook fires it will POST to the URL you specify during the creation of the webhook. - | - |Inside the payload you will find account_id and transaction_id and also user_ids and customer_ids of the Users / Customers linked to the Account. - | | - |The webhook will POST the following structure to your service: - | - |{ - | "event_name": "OnCreateTransaction", - | "event_id": "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", - | "bank_id": "gh.29.uk", - | "account_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", - | "transaction_id": "7ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", - | "related_entities": [ - | { - | "user_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", - | "customer_ids": ["3ca9a7e4-6d02-40e3-a129-0b2bf89de9b1"] - | } - | ] - |} - | - |Thus, your service should accept the above POST body structure. - | - |In this way, your web service can be informed about an event on an account and act accordingly. - | - |Further information about the account, transaction or related entities can then be retrieved using the standard REST APIs. - |""" - - staticResourceDocs += ResourceDoc( - createSystemAccountNotificationWebhook, - implementedInApiVersion, - nameOf(createSystemAccountNotificationWebhook), - "POST", - "/web-hooks/account/notifications/on-create-transaction", - "Create system level Account Notification Webhook", - s""" - |Create a notification Webhook that will fire for all accounts on the system. - | - |$generalWebHookInfo - | - |$accountNotificationWebhookInfo - | - |""", - accountNotificationWebhookPostJson, - systemAccountNotificationWebhookJson, - List(UnknownError), - apiTagWebhook :: apiTagBank :: Nil, - Some(List(canCreateSystemAccountNotificationWebhook)) - ) - - lazy val createSystemAccountNotificationWebhook: OBPEndpoint = { - case "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - failMsg = - s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountNotificationWebhookPostJson] - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})", - cc = callContext - ) { - postJson.http_method.equals("POST") - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})", - cc = callContext - ) { - postJson.http_protocol.equals("HTTP/1.1") - } - onCreateTransaction = ApiTrigger.onCreateTransaction.toString() - wh <- - SystemAccountNotificationWebhookTrait.systemAccountNotificationWebhook.vend - .createSystemAccountNotificationWebhookFuture( - userId = u.userId, - triggerName = onCreateTransaction, - url = postJson.url, - httpMethod = postJson.http_method, - httpProtocol = postJson.http_protocol - ) map { - unboxFullOrFail(_, callContext, CreateWebhookError) - } - } yield { - ( - createSystemLevelAccountWebhookJsonV400(wh), - HttpCode.`201`(callContext) - ) - } - } - } - - staticResourceDocs += ResourceDoc( - createBankAccountNotificationWebhook, - implementedInApiVersion, - nameOf(createBankAccountNotificationWebhook), - "POST", - "/banks/BANK_ID/web-hooks/account/notifications/on-create-transaction", - "Create bank level Account Notification Webhook", - s"""Create a notification Webhook that will fire for all accounts on the specified Bank. - | - |$generalWebHookInfo - | - |$accountNotificationWebhookInfo - | - |""", - accountNotificationWebhookPostJson, - bankAccountNotificationWebhookJson, - List( - AuthenticatedUserIsRequired, - $BankNotFound, - UnknownError - ), - apiTagWebhook :: apiTagBank :: Nil, - Some(List(canCreateAccountNotificationWebhookAtOneBank)) - ) - - lazy val createBankAccountNotificationWebhook: OBPEndpoint = { - case "banks" :: BankId( - bankId - ) :: "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => { - cc => - implicit val ec = EndpointContext(Some(cc)) - for { - (Full(u), callContext) <- authenticatedAccess(cc) - failMsg = - s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson " - postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[AccountNotificationWebhookPostJson] - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})", - cc = callContext - ) { - postJson.http_method.equals("POST") - } - _ <- Helper.booleanToFuture( - failMsg = - s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})", - cc = callContext - ) { - postJson.http_protocol.equals("HTTP/1.1") - } - onCreateTransaction = ApiTrigger.onCreateTransaction.toString() - wh <- - BankAccountNotificationWebhookTrait.bankAccountNotificationWebhook.vend - .createBankAccountNotificationWebhookFuture( - bankId = bankId.value, - userId = u.userId, - triggerName = onCreateTransaction, - url = postJson.url, - httpMethod = postJson.http_method, - httpProtocol = postJson.http_protocol - ) map { - unboxFullOrFail(_, callContext, CreateWebhookError) - } - } yield { - ( - createBankLevelAccountWebhookJsonV400(wh), - HttpCode.`201`(callContext) - ) - } - } - } - - } - - private def checkRoleBankIdExsiting( - callContext: Option[CallContext], - entitlement: CreateEntitlementJSON - ) = { - Helper.booleanToFuture( - failMsg = s"$BankNotFound Current BANK_ID (${entitlement.bank_id})", - cc = callContext - ) { - entitlement.bank_id.nonEmpty == false || BankX( - BankId(entitlement.bank_id), - callContext - ).map(_._1).isEmpty == false - } - } - - private def checkRolesBankIdExsiting( - callContext: Option[CallContext], - postedData: PostCreateUserWithRolesJsonV400 - ) = { - Future.sequence( - postedData.roles.map(checkRoleBankIdExsiting(callContext, _)) - ) - } - - private def addEntitlementToUser( - userId: String, - entitlement: CreateEntitlementJSON, - callContext: Option[CallContext] - ) = { - Future( - Entitlement.entitlement.vend - .addEntitlement(entitlement.bank_id, userId, entitlement.role_name) - ) map { unboxFull(_) } - } - - private def addEntitlementsToUser( - userId: String, - postedData: PostCreateUserWithRolesJsonV400, - callContext: Option[CallContext] - ) = { - Future.sequence( - postedData.roles.distinct.map( - addEntitlementToUser(userId, _, callContext) - ) - ) - } - - /** This method will check all the roles the request user already has and the - * request roles: It will find the roles the requestUser already have, then - * show the error to the developer. (We can not grant the same roles to the - * request user twice) - */ - private def assertTargetUserLacksRoles( - userId: String, - requestedEntitlements: List[CreateEntitlementJSON], - callContext: Option[CallContext] - ) = { - // 1st: get all the entitlements for the user: - val userEntitlements = - Entitlement.entitlement.vend.getEntitlementsByUserId(userId) - val userRoles = userEntitlements - .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId))) - .getOrElse(List.empty[(String, String)]) - .toSet - - val targetRoles = requestedEntitlements - .map(entitlement => (entitlement.role_name, entitlement.bank_id)) - .toSet - - // 2rd: find the duplicated ones: - val duplicatedRoles = userRoles.filter(targetRoles) - - // 3rd: We can not grant the roles again, so we show the error to the developer. - if (duplicatedRoles.size > 0) { - val errorMessages = - s"$EntitlementAlreadyExists user_id($userId) ${duplicatedRoles.mkString(",")}" - Helper.booleanToFuture(errorMessages, cc = callContext) { false } - } else - Future.successful(Full(())) - } - - /** This method will check all the roles the loggedIn user already has and the - * request roles: It will find the not existing roles from the loggedIn user - * --> we will show the error to the developer (We can only grant the roles - * which the loggedIn User has to the requestUser) - */ - private def assertUserCanGrantRoles( - userId: String, - requestedEntitlements: List[CreateEntitlementJSON], - callContext: Option[CallContext] - ) = { - // 1st: get all the entitlements for the user: - val userEntitlements = - Entitlement.entitlement.vend.getEntitlementsByUserId(userId) - val userRoles = userEntitlements - .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId))) - .getOrElse(List.empty[(String, String)]) - .toSet - - val targetRoles = requestedEntitlements - .map(entitlement => (entitlement.role_name, entitlement.bank_id)) - .toSet - - // 2rd: find the roles which the loggedIn user does not have, - val roleLacking = targetRoles.filterNot(userRoles) - - if (roleLacking.size > 0) { - val errorMessages = - s"$EntitlementCannotBeGranted user_id($userId). The login user does not have the following roles: ${roleLacking - .mkString(",")}" - Helper.booleanToFuture(errorMessages, cc = callContext) { false } - } else - Future.successful(Full(())) - } - - private def checkRoleBankIdMapping( - callContext: Option[CallContext], - entitlement: CreateEntitlementJSON - ) = { - Helper.booleanToFuture( - failMsg = - if (ApiRole.valueOf(entitlement.role_name).requiresBankId) - EntitlementIsBankRole - else EntitlementIsSystemRole, - cc = callContext - ) { - ApiRole - .valueOf(entitlement.role_name) - .requiresBankId == entitlement.bank_id.nonEmpty - } - } - - private def checkRoleBankIdMappings( - callContext: Option[CallContext], - postedData: PostCreateUserWithRolesJsonV400 - ) = { - Future.sequence( - postedData.roles.map(checkRoleBankIdMapping(callContext, _)) - ) - } - - private def checkRoleName( - callContext: Option[CallContext], - entitlement: CreateEntitlementJSON - ) = { - Future { - tryo { - valueOf(entitlement.role_name) - } - } map { - val msg = - IncorrectRoleName + entitlement.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted - .mkString(", ") - x => unboxFullOrFail(x, callContext, msg) - } - } - - private def checkRolesName( - callContext: Option[CallContext], - postJsonBody: PostCreateUserWithRolesJsonV400 - ) = { - Future.sequence(postJsonBody.roles.map(checkRoleName(callContext, _))) - } - - private def grantMultpleAccountAccessToUser( - bankId: BankId, - accountId: AccountId, - user: User, - views: List[View], - callContext: Option[CallContext] - ) = { - Future.sequence( - views.map(view => - grantAccountAccessToUser( - bankId: BankId, - accountId: AccountId, - user: User, - view, - callContext: Option[CallContext] - ) - ) - ) - } - - private def getViews( - bankId: BankId, - accountId: AccountId, - postJson: PostCreateUserAccountAccessJsonV400, - callContext: Option[CallContext] - ) = { - Future.sequence( - postJson.views.map(view => - getView( - bankId: BankId, - accountId: AccountId, - view: PostViewJsonV400, - callContext: Option[CallContext] - ) - ) - ) - } - - private def createDynamicEndpointMethod( - bankId: Option[String], - json: JValue, - cc: CallContext - ) = { - for { - (postedJson, openAPI) <- NewStyle.function.tryons( - InvalidJsonFormat + "The request json is not valid OpenAPIV3.0.x or Swagger 2.0.x Please check it in Swagger Editor or similar tools ", - 400, - cc.callContext - ) { - // If it is bank level, we manually added /banks/bankId in all the paths: - val jsonTweakedPath = - DynamicEndpointHelper.addedBankToPath(json, bankId) - val swaggerContent = compactRender(jsonTweakedPath) - - ( - DynamicEndpointSwagger(swaggerContent), - DynamicEndpointHelper.parseSwaggerContent(swaggerContent) - ) - } - duplicatedUrl = DynamicEndpointHelper - .findExistingDynamicEndpoints(openAPI) - .map(kv => s"${kv._1}:${kv._2}") - errorMsg = s"""$DynamicEndpointExists Duplicated ${if ( - duplicatedUrl.size > 1 - ) "endpoints" - else "endpoint"}: ${duplicatedUrl.mkString("; ")}""" - _ <- Helper.booleanToFuture(errorMsg, cc = cc.callContext) { - duplicatedUrl.isEmpty - } - dynamicEndpointInfo <- NewStyle.function.tryons( - InvalidJsonFormat + "Can not convert to OBP Internal Resource Docs", - 400, - cc.callContext - ) { - DynamicEndpointHelper.buildDynamicEndpointInfo( - openAPI, - "current_request_json_body", - bankId - ) - } - roles <- NewStyle.function.tryons( - InvalidJsonFormat + "Can not generate OBP roles", - 400, - cc.callContext - ) { - DynamicEndpointHelper.getRoles(dynamicEndpointInfo) - } - _ <- NewStyle.function.tryons( - InvalidJsonFormat + "Can not generate OBP external Resource Docs", - 400, - cc.callContext - ) { - JSONFactory1_4_0.createResourceDocsJson( - dynamicEndpointInfo.resourceDocs.toList, - false, - None - ) - } - (dynamicEndpoint, callContext) <- NewStyle.function.createDynamicEndpoint( - bankId, - cc.userId, - postedJson.swaggerString, - cc.callContext - ) - _ <- NewStyle.function.tryons( - InvalidJsonFormat + s"Can not grant these roles ${roles.toString} ", - 400, - cc.callContext - ) { - roles.map(role => - Entitlement.entitlement.vend - .addEntitlement(bankId.getOrElse(""), cc.userId, role.toString()) - ) - } - } yield { - val swaggerJson = parse(dynamicEndpoint.swaggerString) - val responseJson: JObject = ( - "bank_id", - dynamicEndpoint.bankId - ) ~ ("user_id", cc.userId) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) - (responseJson, HttpCode.`201`(callContext)) - } - } +/** + * All v4.0.0 Lift endpoints have been migrated to Http4s400. + * This stub is kept so that existing test files that import + * APIMethods400.Implementations4_0_0 continue to compile. + */ +object APIMethods400 { + val Implementations4_0_0 = Http4s400.Implementations4_0_0 } -object APIMethods400 extends RestHelper with APIMethods400 { - lazy val newStyleEndpoints: List[(String, String)] = - Implementations4_0_0.resourceDocs.map { rd => - (rd.partialFunctionName, rd.implementedInApiVersion.toString()) - }.toList - -} +trait APIMethods400 + +// ─── Original Lift implementation (commented out) ──────────────────────────── +//package code.api.v4_0_0 +// +//import scala.language.reflectiveCalls +//import code.DynamicData.DynamicData +//import code.DynamicEndpoint.DynamicEndpointSwagger +//import code.accountattribute.AccountAttributeX +//import code.api.Constant._ +//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON +//import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _} +//import code.api.dynamic.endpoint.helper.practise.{DynamicEndpointCodeGenerator, PractiseEndpoint} +//import code.api.dynamic.endpoint.helper.{CompiledObjects, DynamicEndpointHelper} +//import code.api.dynamic.entity.helper.DynamicEntityInfo +//import code.api.util.APIUtil.{fullBoxOrException, _} +//import code.api.util.ApiRole._ +//import code.api.util.ApiTag._ +//import code.api.util.CommonsEmailWrapper._ +//import code.api.util.DynamicUtil.Validation +//import code.api.util.ErrorMessages.{BankNotFound, _} +//import code.api.util.ExampleValue._ +//import code.api.util.FutureUtil.EndpointContext +//import code.api.util.Glossary.getGlossaryItem +//import code.api.util.NewStyle.HttpCode +//import code.api.util.NewStyle.function._ +//import code.api.util._ +//import code.api.util.migration.Migration +//import code.api.util.newstyle.AttributeDefinition._ +//import code.api.util.newstyle.Consumer._ +//import code.api.util.newstyle.UserCustomerLinkNewStyle.getUserCustomerLinks +//import code.api.util.newstyle.{BalanceNewStyle, UserCustomerLinkNewStyle, ViewNewStyle} +//import code.api.v1_2_1.{JSONFactory, PostTransactionTagJSON} +//import code.api.v1_4_0.JSONFactory1_4_0 +//import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0 +//import code.api.v2_0_0.{CreateEntitlementJSON, CreateUserCustomerLinkJson, EntitlementJSONs, JSONFactory200} +//import code.api.v2_1_0._ +//import code.api.v3_0_0.{CreateScopeJson, JSONFactory300} +//import code.api.v3_1_0._ +//import code.api.v4_0_0.JSONFactory400._ +//import code.api.{Constant, JsonResponseException} +//import code.apicollection.MappedApiCollectionsProvider +//import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider +//import code.authtypevalidation.JsonAuthTypeValidation +//import code.bankconnectors.LocalMappedConnectorInternal._ +//import code.bankconnectors.{Connector, DynamicConnector, InternalConnector, LocalMappedConnectorInternal} +//import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody} +//import code.consent.{ConsentStatus, Consents, DoobieConsentQueries} +//import code.dynamicEntity.DynamicEntityCommons +//import code.dynamicMessageDoc.JsonDynamicMessageDoc +//import code.dynamicResourceDoc.JsonDynamicResourceDoc +//import code.endpointMapping.EndpointMappingCommons +//import code.entitlement.Entitlement +//import code.loginattempts.LoginAttempt +//import code.metadata.counterparties.{Counterparties, MappedCounterparty} +//import code.metadata.tags.Tags +//import code.model._ +//import code.model.dataAccess.{AuthUser, BankAccountCreation} +//import code.ratelimiting.RateLimitingDI +//import code.scope.Scope +//// Removed: import code.snippet.{WebUIPlaceholder, WebUITemplate} - portal pages removed +//import code.usercustomerlinks.UserCustomerLink +//import code.userlocks.UserLocksProvider +//import code.users.Users +//import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN, booleanToFuture} +//import code.util.{Helper, JsonSchemaUtil} +//import code.validation.JsonValidation +//import code.views.Views +//import code.webhook.{BankAccountNotificationWebhookTrait, SystemAccountNotificationWebhookTrait} +//import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue +//import com.github.dwickern.macros.NameOf.nameOf +//import com.networknt.schema.ValidationMessage +//import com.openbankproject.commons.ExecutionContext.Implicits.global +//import com.openbankproject.commons.dto.GetProductsParam +//import com.openbankproject.commons.model._ +//import com.openbankproject.commons.model.enums.DynamicEntityOperation._ +//import com.openbankproject.commons.model.enums.TransactionRequestTypes._ +//import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _} +//import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion} +//import deletion._ +//import net.liftweb.common._ +//import net.liftweb.http.rest.RestHelper +//import net.liftweb.json.JsonAST.JValue +//import net.liftweb.json.JsonDSL._ +//import net.liftweb.json._ +//import net.liftweb.util.Helpers.{now, tryo} +//import net.liftweb.util.{Helpers, StringHelpers} +//import org.apache.commons.lang3.StringUtils +// +//import java.net.URLEncoder +//import java.text.SimpleDateFormat +//import java.util +//import java.util.{Calendar, Date} +//import scala.collection.JavaConverters._ +//import scala.collection.immutable.{List, Nil} +//import scala.collection.mutable.ArrayBuffer +//import scala.concurrent.Future +// +//trait APIMethods400 extends MdcLoggable { +// self: RestHelper => +// +// val Implementations4_0_0 = new Implementations400() +// +// // Email template constants (moved from removed WebUITemplate/WebUIPlaceholder snippets) +// private val EMAIL_RECIPIENT_PLACEHOLDER = "{{email_recipient}}" +// private val ACTIVATE_ACCOUNT_PLACEHOLDER = "{{activate_your_account}}" +// private val DEFAULT_EMAIL_TEXT = s"Dear $EMAIL_RECIPIENT_PLACEHOLDER, please activate your account: $ACTIVATE_ACCOUNT_PLACEHOLDER" +// private val DEFAULT_EMAIL_HTML = s"

Dear $EMAIL_RECIPIENT_PLACEHOLDER,

Please activate your account: Activate

" +// +// +// class Implementations400 { +// +// val implementedInApiVersion = ApiVersion.v4_0_0 +// +// // DRY constants for dynamic entity documentation +// private val dynamicEntityNamingExplanation = +// """**IMPORTANT: Entity Naming** +// |In the examples below, "AgentConversation" and "AgentMessage" are example entity names. You should replace these with your own entity name (e.g., "Event", "Price", "Order", "Invoice"). The entity name you choose will become the API endpoint name and must be a valid identifier.""".stripMargin +// +// private val dynamicEntityImportantNotes = +// """**Important Notes:** +// |- **Entity name is your choice**: "AgentConversation", "FooBar", etc. are just examples. Replace with YOUR entity name (e.g., "Event", "Price", "Invoice") +// |- **Entity name becomes the endpoint**: If you create an entity called "Invoice", OBP will generate endpoints like `/obp/dynamic-entity/Invoice`, `POST /obp/dynamic-entity/Invoice`, etc. +// |- The entity name (e.g., "AgentConversation") MUST be a direct top-level key in the JSON root object +// |- Do NOT wrap the entity in an "entity" field - this is a common mistake +// |- Do NOT include "entityName" as a separate field +// |- The JSON root can contain at most TWO fields: your entity name and optionally "hasPersonalEntity" +// |- The "properties" object contains all field definitions +// |- Each property must have "type" and "example" fields. The "description" field is optional +// |- For boolean fields, the example must be the STRING "true" or "false" (not boolean values) +// |- The "hasPersonalEntity" field is optional (defaults to true) and goes at the root level""".stripMargin +// +// private val dynamicEntityGeneratedTags = +// """**Tags Generated for CRUD Endpoints:** +// |When you create a dynamic entity, the resulting CRUD endpoints (GET all, GET one, POST, PUT, DELETE) will automatically be tagged with THREE tags: +// |1. **Entity-specific tag** - Based on your entity name (e.g., "Piano", "Invoice", "AgentConversation") +// |2. **"Dynamic-Entity"** - Groups all dynamic entity endpoints together +// |3. **"Dynamic"** - Groups all dynamic endpoints (both entities and endpoints) +// | +// |These tags help organize and filter endpoints in the API Explorer.""".stripMargin +// +// private val dynamicEntityPianoExample = +// """ +// |**Example 3: Piano Entity Demonstrating Different Field Types** +// |```json +// |{ +// | "Piano": { +// | "description": "Piano entity with make, year, number of keys, and type", +// | "required": ["make", "year", "number_of_keys", "is_grand", "date_purchased", "weight_in_kg"], +// | "properties": { +// | "make": { +// | "type": "string", +// | "example": "Steinway" +// | }, +// | "year": { +// | "type": "string", +// | "example": "2023" +// | }, +// | "number_of_keys": { +// | "type": "integer", +// | "example": 88 +// | }, +// | "is_grand": { +// | "type": "boolean", +// | "example": "true" +// | }, +// | "date_purchased": { +// | "type": "DATE_WITH_DAY", +// | "example": "2023-06-15" +// | }, +// | "weight_in_kg": { +// | "type": "number", +// | "example": 480.5 +// | } +// | } +// | }, +// | "hasPersonalEntity": true +// |} +// |```""".stripMargin +// +// private val staticResourceDocs = ArrayBuffer[ResourceDoc]() +// // createDynamicEntityDoc and updateDynamicEntityDoc are dynamic, So here dynamic create resourceDocs +// def resourceDocs = staticResourceDocs ++ ArrayBuffer[ResourceDoc]( +// createDynamicEntityDoc, +// createBankLevelDynamicEntityDoc, +// updateDynamicEntityDoc, +// updateBankLevelDynamicEntityDoc, +// updateMyDynamicEntityDoc +// ) +// +// val apiRelations = ArrayBuffer[ApiRelation]() +// val codeContext = CodeContext(staticResourceDocs, apiRelations) +// +// staticResourceDocs += ResourceDoc( +// getMapperDatabaseInfo, +// implementedInApiVersion, +// nameOf(getMapperDatabaseInfo), +// "GET", +// "/database/info", +// "Get Mapper Database Info", +// s"""Get basic information about the Mapper Database. +// | +// |${userAuthenticationMessage(true)} +// | +// """.stripMargin, +// EmptyBody, +// adapterInfoJsonV300, +// List($AuthenticatedUserIsRequired, UnknownError), +// List(apiTagApi), +// Some(List(canGetDatabaseInfo)) +// ) +// +// lazy val getMapperDatabaseInfo: OBPEndpoint = { +// case "database" :: "info" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// Future { +// ( +// Migration.DbFunction.mapperDatabaseInfo, +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getLogoutLink, +// implementedInApiVersion, +// nameOf( +// getLogoutLink +// ), // TODO can we get this string from the val two lines above? +// "GET", +// "/users/current/logout-link", +// "Get Logout Link", +// s"""Get the Logout Link +// | +// |${userAuthenticationMessage(true)} +// """.stripMargin, +// EmptyBody, +// logoutLinkV400, +// List($AuthenticatedUserIsRequired, UnknownError), +// List(apiTagUser) +// ) +// +// lazy val getLogoutLink: OBPEndpoint = { +// case "users" :: "current" :: "logout-link" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// Future { +// val link = code.api.Constant.HostName + AuthUser.logoutPath.foldLeft( +// "" +// )(_ + "/" + _) +// val logoutLink = LogoutLinkJson(link) +// (logoutLink, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// callsLimit, +// implementedInApiVersion, +// nameOf(callsLimit), +// "PUT", +// "/management/consumers/CONSUMER_ID/consumer/call-limits", +// "Set Rate Limits / Call Limits per Consumer", +// s""" +// |Set the API rate limits / call limits for a Consumer: +// | +// |Rate limiting can be set: +// | +// |Per Second +// |Per Minute +// |Per Hour +// |Per Week +// |Per Month +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// callLimitPostJsonV400, +// callLimitPostJsonV400, +// List( +// AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// InvalidConsumerId, +// ConsumerNotFoundByConsumerId, +// UserHasMissingRoles, +// UpdateConsumerError, +// UnknownError +// ), +// List(apiTagConsumer, apiTagRateLimits), +// Some(List(canUpdateRateLimits)) +// ) +// +// lazy val callsLimit: OBPEndpoint = { +// case "management" :: "consumers" :: consumerId :: "consumer" :: "call-limits" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.handleEntitlementsAndScopes( +// "", +// u.userId, +// List(canUpdateRateLimits), +// callContext +// ) +// postJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $CallLimitPostJsonV400 ", +// 400, +// callContext +// ) { +// json.extract[CallLimitPostJsonV400] +// } +// _ <- NewStyle.function.getConsumerByConsumerId( +// consumerId, +// callContext +// ) +// rateLimiting <- RateLimitingDI.rateLimiting.vend +// .createOrUpdateConsumerCallLimits( +// consumerId, +// postJson.from_date, +// postJson.to_date, +// postJson.api_version, +// postJson.api_name, +// postJson.bank_id, +// Some(postJson.per_second_call_limit), +// Some(postJson.per_minute_call_limit), +// Some(postJson.per_hour_call_limit), +// Some(postJson.per_day_call_limit), +// Some(postJson.per_week_call_limit), +// Some(postJson.per_month_call_limit) +// ) map { +// unboxFullOrFail(_, callContext, UpdateConsumerError) +// } +// } yield { +// (createCallsLimitJson(rateLimiting), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBanks, +// implementedInApiVersion, +// nameOf(getBanks), +// "GET", +// "/banks", +// "Get Banks", +// """Get banks on this API instance +// |Returns a list of banks supported on this server: +// | +// |* ID used as parameter in URLs +// |* Short and full name of bank +// |* Logo URL +// |* Website""", +// EmptyBody, +// banksJSON400, +// List(UnknownError), +// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil +// ) +// +// lazy val getBanks: OBPEndpoint = { +// case "banks" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (banks, callContext) <- NewStyle.function.getBanks(cc.callContext) +// } yield { +// (JSONFactory400.createBanksJson(banks), HttpCode.`200`(callContext)) +// } +// +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBank, +// implementedInApiVersion, +// nameOf(getBank), +// "GET", +// "/banks/BANK_ID", +// "Get Bank", +// """Get the bank specified by BANK_ID +// |Returns information about a single bank specified by BANK_ID including: +// | +// |* Short and full name of bank +// |* Logo URL +// |* Website""", +// EmptyBody, +// bankJson400, +// List(UnknownError, BankNotFound), +// apiTagBank :: apiTagPSD2AIS :: apiTagPsd2 :: Nil +// ) +// +// lazy val getBank: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (bank, callContext) <- NewStyle.function.getBank( +// bankId, +// cc.callContext +// ) +// (attributes, callContext) <- NewStyle.function +// .getBankAttributesByBank(bankId, callContext) +// } yield ( +// JSONFactory400.createBankJSON400(bank, attributes), +// HttpCode.`200`(callContext) +// ) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// ibanChecker, +// implementedInApiVersion, +// nameOf(ibanChecker), +// "POST", +// "/account/check/scheme/iban", +// "Validate and check IBAN", +// """Validate and check IBAN for errors +// | +// |""", +// ibanCheckerPostJsonV400, +// ibanCheckerJsonV400, +// List(UnknownError), +// apiTagAccount :: Nil +// ) +// +// lazy val ibanChecker: OBPEndpoint = { +// case "account" :: "check" :: "scheme" :: "iban" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(ibanCheckerPostJsonV400))}" +// for { +// ibanJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[IbanAddress] +// } +// (ibanChecker, callContext) <- NewStyle.function +// .validateAndCheckIbanNumber(ibanJson.address, cc.callContext) +// } yield { +// ( +// JSONFactory400.createIbanCheckerJson(ibanChecker), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getDoubleEntryTransaction, +// implementedInApiVersion, +// nameOf(getDoubleEntryTransaction), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions/TRANSACTION_ID/double-entry-transaction", +// "Get Double Entry Transaction", +// s"""Get Double Entry Transaction +// | +// |This endpoint can be used to see the double entry transactions. It returns the `bank_id`, `account_id` and `transaction_id` +// |for the debit end the credit transaction. The other side account can be a settlement account or an OBP account. +// | +// |The endpoint also provide the `transaction_request` object which contains the `bank_id`, `account_id` and +// |`transaction_request_id` of the transaction request at the origin of the transaction. Please note that if none +// |transaction request is at the origin of the transaction, the `transaction_request` object will be `null`. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// doubleEntryTransactionJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction), +// Some( +// List( +// canGetDoubleEntryTransactionAtAnyBank, +// canGetDoubleEntryTransactionAtOneBank +// ) +// ) +// ) +// +// lazy val getDoubleEntryTransaction: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transactions" :: TransactionId( +// transactionId +// ) :: "double-entry-transaction" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// (doubleEntryTransaction, callContext) <- NewStyle.function +// .getDoubleEntryBookTransaction( +// bankId, +// accountId, +// transactionId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createDoubleEntryTransactionJson( +// doubleEntryTransaction +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// staticResourceDocs += ResourceDoc( +// getBalancingTransaction, +// implementedInApiVersion, +// nameOf(getBalancingTransaction), +// "GET", +// "/transactions/TRANSACTION_ID/balancing-transaction", +// "Get Balancing Transaction", +// s"""Get Balancing Transaction +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// doubleEntryTransactionJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction), +// Some(List()) +// ) +// +// lazy val getBalancingTransaction: OBPEndpoint = { +// case "transactions" :: TransactionId( +// transactionId +// ) :: "balancing-transaction" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (doubleEntryTransaction, callContext) <- NewStyle.function +// .getBalancingTransaction(transactionId, cc.callContext) +// _ <- ViewNewStyle.checkBalancingTransactionAccountAccessAndReturnView( +// doubleEntryTransaction, +// cc.user, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createDoubleEntryTransactionJson( +// doubleEntryTransaction +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createSettlementAccount, +// implementedInApiVersion, +// nameOf(createSettlementAccount), +// "POST", +// "/banks/BANK_ID/settlement-accounts", +// "Create Settlement Account", +// s"""Create a new settlement account at a bank. +// | +// |The created settlement account id will be the concatenation of the payment system and the account currency. +// |For examples: SEPA_SETTLEMENT_ACCOUNT_EUR, CARD_SETTLEMENT_ACCOUNT_USD +// | +// |By default, when you create a new bank, two settlements accounts are created automatically: OBP_DEFAULT_INCOMING_ACCOUNT_ID and OBP_DEFAULT_OUTGOING_ACCOUNT_ID +// |Those two accounts have EUR as default currency. +// | +// |If you want to create default settlement account for a specific currency, you can fill the `payment_system` field with the `DEFAULT` value. +// | +// |When a transaction is saved in OBP through the mapped connector, OBP-API look for the account to save the double-entry transaction. +// |If no OBP account can be found from the counterparty, the double-entry transaction will be saved on a bank settlement account. +// |- First, the mapped connector looks for a settlement account specific to the payment system and currency. E.g SEPA_SETTLEMENT_ACCOUNT_EUR. +// |- If we don't find any specific settlement account with the payment system, we look for a default settlement account for the counterparty currency. E.g DEFAULT_SETTLEMENT_ACCOUNT_EUR. +// |- Else, we select one of the two OBP default settlement accounts (OBP_DEFAULT_INCOMING_ACCOUNT_ID/OBP_DEFAULT_OUTGOING_ACCOUNT_ID) according to the transaction direction. +// | +// |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID. +// | +// |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User. +// | +// |Note: The Amount MUST be zero. +// |""".stripMargin, +// settlementAccountRequestJson, +// settlementAccountResponseJson, +// List( +// InvalidJsonFormat, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// $BankNotFound, +// InvalidAccountInitialBalance, +// InitialBalanceMustBeZero, +// InvalidISOCurrencyCode, +// UnknownError +// ), +// List(apiTagBank), +// Some(List(canCreateSettlementAccountAtOneBank)) +// ) +// +// lazy val createSettlementAccount: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "settlement-accounts" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(settlementAccountRequestJson))}" +// for { +// createAccountJson <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[SettlementAccountRequestJson] +// } +// loggedInUserId = cc.userId +// userIdAccountOwner = +// if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id +// else loggedInUserId +// (postedOrLoggedInUser, callContext) <- NewStyle.function.findByUserId( +// userIdAccountOwner, +// cc.callContext +// ) +// +// _ <- +// if (userIdAccountOwner == loggedInUserId) +// Future.successful(Full(Unit)) +// else +// NewStyle.function.hasEntitlement( +// bankId.value, +// loggedInUserId, +// canCreateSettlementAccountAtOneBank, +// callContext +// ) +// +// initialBalanceAsString = createAccountJson.balance.amount +// accountLabel = createAccountJson.label +// initialBalanceAsNumber <- NewStyle.function.tryons( +// InvalidAccountInitialBalance, +// 400, +// callContext +// ) { +// BigDecimal(initialBalanceAsString) +// } +// _ <- Helper.booleanToFuture( +// InitialBalanceMustBeZero, +// cc = callContext +// ) { 0 == initialBalanceAsNumber } +// currency = createAccountJson.balance.currency +// _ <- Helper.booleanToFuture( +// InvalidISOCurrencyCode, +// cc = callContext +// ) { APIUtil.isValidCurrencyISOCode(currency) } +// +// (_, callContext) <- NewStyle.function.getBank(bankId, callContext) +// _ <- Helper.booleanToFuture( +// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", +// cc = callContext +// ) { +// createAccountJson.account_routings +// .map(_.scheme) +// .distinct +// .size == createAccountJson.account_routings.size +// } +// alreadyExistAccountRoutings <- Future.sequence( +// createAccountJson.account_routings.map(accountRouting => +// NewStyle.function +// .getAccountRouting( +// Some(bankId), +// accountRouting.scheme, +// accountRouting.address, +// callContext +// ) +// .map(_ => Some(accountRouting)) +// .fallbackTo(Future.successful(None)) +// ) +// ) +// alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect { +// case Some(accountRouting) => +// s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" +// } +// _ <- Helper.booleanToFuture( +// s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", +// cc = callContext +// ) { +// alreadyExistingAccountRouting.isEmpty +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", +// cc = callContext +// ) { +// createAccountJson.account_routings +// .map(_.scheme) +// .distinct +// .size == createAccountJson.account_routings.size +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidPaymentSystemName Space characters are not allowed.", +// cc = callContext +// ) { +// !createAccountJson.payment_system.contains(" ") +// } +// accountId = AccountId( +// createAccountJson.payment_system.toUpperCase + "_SETTLEMENT_ACCOUNT_" + currency.toUpperCase +// ) +// (bankAccount, callContext) <- NewStyle.function.createBankAccount( +// bankId, +// accountId, +// "SETTLEMENT", +// accountLabel, +// currency, +// initialBalanceAsNumber, +// postedOrLoggedInUser.name, +// createAccountJson.branch_id, +// createAccountJson.account_routings.map(r => +// AccountRouting(r.scheme, r.address) +// ), +// callContext +// ) +// accountId = bankAccount.accountId +// (productAttributes, callContext) <- NewStyle.function +// .getProductAttributesByBankAndCode( +// bankId, +// ProductCode("SETTLEMENT"), +// callContext +// ) +// (accountAttributes, callContext) <- NewStyle.function +// .createAccountAttributes( +// bankId, +// accountId, +// ProductCode("SETTLEMENT"), +// productAttributes, +// None, +// callContext: Option[CallContext] +// ) +// // 1 Create or Update the `Owner` for the new account +// // 2 Add permission to the user +// // 3 Set the user as the account holder +// _ <- BankAccountCreation.setAccountHolderAndRefreshUserAccountAccess( +// bankId, +// accountId, +// postedOrLoggedInUser, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createSettlementAccountJson( +// userIdAccountOwner, +// bankAccount, +// accountAttributes +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getSettlementAccounts, +// implementedInApiVersion, +// nameOf(getSettlementAccounts), +// "GET", +// "/banks/BANK_ID/settlement-accounts", +// "Get Settlement accounts at Bank", +// """Get settlement accounts on this API instance +// |Returns a list of settlement accounts at this Bank +// | +// |Note: a settlement account is considered as a bank account. +// |So you can update it and add account attributes to it using the regular account endpoints +// |""", +// EmptyBody, +// settlementAccountsJson, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagBank, apiTagPsd2), +// Some(List(canGetSettlementAccountAtOneBank)) +// ) +// +// lazy val getSettlementAccounts: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "settlement-accounts" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- NewStyle.function.hasEntitlement( +// bankId.value, +// cc.userId, +// canGetSettlementAccountAtOneBank, +// cc.callContext +// ) +// +// (accounts, callContext) <- NewStyle.function +// .getBankSettlementAccounts(bankId, cc.callContext) +// settlementAccounts <- Future.sequence(accounts.map(account => { +// NewStyle.function +// .getAccountAttributesByAccount( +// bankId, +// account.accountId, +// callContext +// ) +// .map(accountAttributes => +// JSONFactory400 +// .getSettlementAccountJson(account, accountAttributes._1) +// ) +// })) +// } yield { +// ( +// SettlementAccountsJson(settlementAccounts), +// HttpCode.`200`(callContext) +// ) +// } +// +// } +// } +// +// // ACCOUNT. (we no longer create a resource doc for the general case) +// staticResourceDocs += ResourceDoc( +// createTransactionRequestAccount, +// implementedInApiVersion, +// "createTransactionRequestAccount", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT/transaction-requests", +// "Create Transaction Request (ACCOUNT)", +// s"""When using ACCOUNT, the payee is set in the request body. +// | +// |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body. +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyJsonV200, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// // ACCOUNT_OTP. (we no longer create a resource doc for the general case) +// staticResourceDocs += ResourceDoc( +// createTransactionRequestAccountOtp, +// implementedInApiVersion, +// "createTransactionRequestAccountOtp", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/ACCOUNT_OTP/transaction-requests", +// "Create Transaction Request (ACCOUNT_OTP)", +// s"""When using ACCOUNT, the payee is set in the request body. +// | +// |Money goes into the BANK_ID and ACCOUNT_ID specified in the request body. +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyJsonV200, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// // COUNTERPARTY +// staticResourceDocs += ResourceDoc( +// createTransactionRequestCounterparty, +// implementedInApiVersion, +// "createTransactionRequestCounterparty", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/COUNTERPARTY/transaction-requests", +// "Create Transaction Request (COUNTERPARTY)", +// s""" +// |$transactionRequestGeneralText +// | +// |When using a COUNTERPARTY to create a Transaction Request, specify the counterparty_id in the body of the request. +// |The routing details of the counterparty will be forwarded to the Core Banking System (CBS) for the transfer. +// | +// |COUNTERPARTY Transaction Requests are used for Variable Recurring Payments (VRP). Use the following ${Glossary +// .getApiExplorerLink( +// "endpoint", +// "OBPv5.1.0-createVRPConsentRequest" +// )} to create a consent for VRPs. +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// """.stripMargin, +// transactionRequestBodyCounterpartyJSON, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// // SIMPLE +// staticResourceDocs += ResourceDoc( +// createTransactionRequestSimple, +// implementedInApiVersion, +// nameOf(createTransactionRequestSimple), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SIMPLE/transaction-requests", +// "Create Transaction Request (SIMPLE)", +// s""" +// |Special instructions for SIMPLE: +// | +// |You can transfer money to the Bank Account Number or IBAN directly. +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodySimpleJsonV400, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// // Transaction Request (SEPA) +// staticResourceDocs += ResourceDoc( +// createTransactionRequestSepa, +// implementedInApiVersion, +// "createTransactionRequestSepa", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/SEPA/transaction-requests", +// "Create Transaction Request (SEPA)", +// s""" +// |Special instructions for SEPA: +// | +// |When using a SEPA Transaction Request, you specify the IBAN of a Counterparty in the body of the request. +// |The routing details (IBAN) of the counterparty will be forwarded to the core banking system for the transfer. +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodySEPAJsonV400, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// staticResourceDocs += ResourceDoc( +// createTransactionRequestRefund, +// implementedInApiVersion, +// nameOf(createTransactionRequestRefund), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/REFUND/transaction-requests", +// "Create Transaction Request (REFUND)", +// s""" +// | +// |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded. +// | +// |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction. +// |In the `from` object, you have two choices : +// |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API +// |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API +// | +// |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent. +// |(This case is not managed by the OBP-API and require an external adapter) +// | +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyRefundJsonV400, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// // FREE_FORM. +// staticResourceDocs += ResourceDoc( +// createTransactionRequestFreeForm, +// implementedInApiVersion, +// "createTransactionRequestFreeForm", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/FREE_FORM/transaction-requests", +// "Create Transaction Request (FREE_FORM)", +// s"""$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyFreeFormJSON, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS), +// Some(List(canCreateAnyTransactionRequest)) +// ) +// +// staticResourceDocs += ResourceDoc( +// createTransactionRequestAgentCashWithDrawal, +// implementedInApiVersion, +// nameOf(createTransactionRequestAgentCashWithDrawal), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/AGENT_CASH_WITHDRAWAL/transaction-requests", +// "Create Transaction Request (AGENT_CASH_WITHDRAWAL)", +// s""" +// | +// |Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded. +// | +// |In case the `from` object is used, it means that the refund comes from the part that sent you a transaction. +// |In the `from` object, you have two choices : +// |- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API +// |- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API +// | +// |In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent. +// |(This case is not managed by the OBP-API and require an external adapter) +// | +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyAgentJsonV400, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// lazy val createTransactionRequestAgentCashWithDrawal: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "AGENT_CASH_WITHDRAWAL" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType( +// "AGENT_CASH_WITHDRAWAL" +// ) +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestAccount: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "ACCOUNT" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("ACCOUNT") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestAccountOtp: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "ACCOUNT_OTP" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("ACCOUNT_OTP") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestSepa: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "SEPA" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("SEPA") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestCounterparty: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "COUNTERPARTY" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("COUNTERPARTY") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestRefund: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "REFUND" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("REFUND") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestFreeForm: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "FREE_FORM" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("FREE_FORM") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// lazy val createTransactionRequestSimple: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// "SIMPLE" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("SIMPLE") +// LocalMappedConnectorInternal.createTransactionRequest( +// bankId, +// accountId, +// viewId, +// transactionRequestType, +// json +// ) +// } +// +// staticResourceDocs += ResourceDoc( +// createTransactionRequestCard, +// implementedInApiVersion, +// nameOf(createTransactionRequestCard), +// "POST", +// "/transaction-request-types/CARD/transaction-requests", +// "Create Transaction Request (CARD)", +// s""" +// | +// |When using CARD, the payee is set in the request body . +// | +// |Money goes into the Counterparty in the request body. +// | +// |$transactionRequestGeneralText +// | +// """.stripMargin, +// transactionRequestBodyCardJsonV400, +// transactionRequestWithChargeJSON400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// AccountNotFound, +// $BankAccountNotFound, +// InsufficientAuthorisationToCreateTransactionRequest, +// InvalidTransactionRequestType, +// InvalidJsonFormat, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// lazy val createTransactionRequestCard: OBPEndpoint = { +// case "transaction-request-types" :: "CARD" :: "transaction-requests" :: Nil JsonPost json -> _ => +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val transactionRequestType = TransactionRequestType("CARD") +// LocalMappedConnectorInternal.createTransactionRequest( +// BankId(""), +// AccountId(""), +// ViewId(Constant.SYSTEM_OWNER_VIEW_ID), +// transactionRequestType, +// json +// ) +// } +// +// staticResourceDocs += ResourceDoc( +// answerTransactionRequestChallenge, +// implementedInApiVersion, +// "answerTransactionRequestChallenge", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge", +// "Answer Transaction Request Challenge", +// s"""In Sandbox mode, any string that can be converted to a positive integer will be accepted as an answer. +// | +// |This endpoint totally depends on createTransactionRequest, it need get the following data from createTransactionRequest response body. +// | +// |1)`TRANSACTION_REQUEST_TYPE` : is the same as createTransactionRequest request URL . +// | +// |2)`TRANSACTION_REQUEST_ID` : is the `id` field in createTransactionRequest response body. +// | +// |3) `id` : is `challenge.id` field in createTransactionRequest response body. +// | +// |4) `answer` : must be `123` in case that Strong Customer Authentication method for OTP challenge is dummy. +// | For instance: SANDBOX_TAN_OTP_INSTRUCTION_TRANSPORT=dummy +// | Possible values are dummy,email and sms +// | In CBS mode, the answer can be got by phone message or other SCA methods. +// | +// |Note that each Transaction Request Type can have its own OTP_INSTRUCTION_TRANSPORT method. +// |OTP_INSTRUCTION_TRANSPORT methods are set in Props. See sample.props.template for instructions. +// | +// |Single or Multiple authorisations +// | +// |OBP allows single or multi party authorisations. +// | +// |Single party authorisation: +// | +// |In the case that only one person needs to authorise i.e. answer a security challenge we have the following change of state of a `transaction request`: +// | INITIATED => COMPLETED +// | +// | +// |Multiparty authorisation: +// | +// |In the case that multiple parties (n persons) need to authorise a transaction request i.e. answer security challenges, we have the followings state flow for a `transaction request`: +// | INITIATED => NEXT_CHALLENGE_PENDING => ... => NEXT_CHALLENGE_PENDING => COMPLETED +// | +// |The security challenge is bound to a user i.e. in the case of a correct answer but the user is different than expected the challenge will fail. +// | +// |Rule for calculating number of security challenges: +// |If Product Account attribute REQUIRED_CHALLENGE_ANSWERS=N then create N challenges +// |(one for every user that has a View where permission $CAN_ADD_TRANSACTION_REQUEST_TO_ANY_ACCOUNT=true) +// |In the case REQUIRED_CHALLENGE_ANSWERS is not defined as an account attribute, the default number of security challenges created is one. +// | +// """.stripMargin, +// challengeAnswerJson400, +// transactionRequestWithChargeJSON210, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// InvalidAccountIdFormat, +// InvalidJsonFormat, +// $BankNotFound, +// $BankAccountNotFound, +// TransactionRequestStatusNotInitiated, +// TransactionRequestTypeHasChanged, +// AllowedAttemptsUsedUp, +// TransactionDisabled, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// lazy val answerTransactionRequestChallenge: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-request-types" :: +// TransactionRequestType( +// transactionRequestType +// ) :: "transaction-requests" :: TransactionRequestId( +// transReqId +// ) :: "challenge" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, fromAccount, callContext) <- SS.userBankAccount +// _ <- NewStyle.function.isEnabledTransactionRequests(callContext) +// _ <- Helper.booleanToFuture( +// InvalidAccountIdFormat, +// cc = callContext +// ) { +// isValidID(accountId.value) +// } +// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { +// isValidID(bankId.value) +// } +// challengeAnswerJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $ChallengeAnswerJson400", +// 400, +// callContext +// ) { +// json.extract[ChallengeAnswerJson400] +// } +// +// account = BankIdAccountId(fromAccount.bankId, fromAccount.accountId) +// _ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest( +// viewId, +// account, +// u, +// callContext +// ) +// +// // Check transReqId is valid +// (existingTransactionRequest, callContext) <- NewStyle.function +// .getTransactionRequestImpl(transReqId, callContext) +// +// // Check the Transaction Request is still INITIATED or NEXT_CHALLENGE_PENDING or FORWARDED +// _ <- Helper.booleanToFuture( +// TransactionRequestStatusNotInitiatedOrPendingOrForwarded, +// cc = callContext +// ) { +// existingTransactionRequest.status.equals( +// TransactionRequestStatus.INITIATED.toString +// ) || +// existingTransactionRequest.status.equals( +// TransactionRequestStatus.NEXT_CHALLENGE_PENDING.toString +// ) || +// existingTransactionRequest.status.equals( +// TransactionRequestStatus.FORWARDED.toString +// ) +// } +// +// // Check Maker/Checker separation if required by the view +// _ <- NewStyle.function.checkMakerCheckerForTransactionRequest( +// bankId, +// accountId, +// viewId, +// transReqId, +// challengeAnswerJson.id, +// u.userId, +// callContext +// ) +// +// // Check the input transactionRequestType is the same as when the user created the TransactionRequest +// existingTransactionRequestType = existingTransactionRequest.`type` +// _ <- Helper.booleanToFuture( +// s"${TransactionRequestTypeHasChanged} It should be :'$existingTransactionRequestType', but current value (${transactionRequestType.value}) ", +// cc = callContext +// ) { +// existingTransactionRequestType.equals(transactionRequestType.value) +// } +// +// (challenges, callContext) <- NewStyle.function +// .getChallengesByTransactionRequestId(transReqId.value, callContext) +// +// // Check the challenge type, Note: not supported yet, the default value is SANDBOX_TAN +// _ <- Helper.booleanToFuture( +// s"$InvalidChallengeType Current Type is ${challenges.map(_.challengeType)}", +// cc = callContext +// ) { +// challenges +// .map(_.challengeType) +// .filterNot(challengeType => +// challengeType.equals( +// ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE.toString +// ) +// ) +// .isEmpty +// } +// +// (transactionRequest, callContext) <- +// challengeAnswerJson.answer match { +// // If the challenge answer is `REJECT` - Currently only to Reject a SEPA transaction request REFUND +// case "REJECT" => +// val transactionRequest = +// existingTransactionRequest.copy(status = +// TransactionRequestStatus.REJECTED.toString +// ) +// for { +// (fromAccount, toAccount, callContext) <- { +// // If the transaction request comes from the account to debit +// if ( +// fromAccount.accountId.value == transactionRequest.from.account_id +// ) { +// val toCounterpartyIban = +// transactionRequest.other_account_routing_address +// for { +// (toCounterparty, callContext) <- NewStyle.function +// .getCounterpartyByIbanAndBankAccountId( +// toCounterpartyIban, +// fromAccount.bankId, +// fromAccount.accountId, +// callContext +// ) +// (toAccount, callContext) <- NewStyle.function +// .getBankAccountFromCounterparty( +// toCounterparty, +// true, +// callContext +// ) +// } yield (fromAccount, toAccount, callContext) +// } else { +// // Else, the transaction request debit a counterparty (Iban) +// val fromCounterpartyIban = +// transactionRequest.from.account_id +// // and the creditor is the obp account owner +// val toAccount = fromAccount +// for { +// (fromCounterparty, callContext) <- NewStyle.function +// .getCounterpartyByIbanAndBankAccountId( +// fromCounterpartyIban, +// toAccount.bankId, +// toAccount.accountId, +// callContext +// ) +// (fromAccount, callContext) <- NewStyle.function +// .getBankAccountFromCounterparty( +// fromCounterparty, +// false, +// callContext +// ) +// } yield (fromAccount, toAccount, callContext) +// } +// } +// rejectReasonCode = challengeAnswerJson.reason_code.getOrElse( +// "" +// ) +// _ <- +// if (rejectReasonCode.nonEmpty) { +// NewStyle.function +// .createOrUpdateTransactionRequestAttribute( +// bankId = bankId, +// transactionRequestId = transactionRequest.id, +// transactionRequestAttributeId = None, +// name = "reject_reason_code", +// attributeType = +// TransactionRequestAttributeType.withName("STRING"), +// value = rejectReasonCode, +// callContext = callContext +// ) +// } else Future.successful(()) +// rejectAdditionalInformation = +// challengeAnswerJson.additional_information.getOrElse("") +// _ <- +// if (rejectAdditionalInformation.nonEmpty) { +// NewStyle.function +// .createOrUpdateTransactionRequestAttribute( +// bankId = bankId, +// transactionRequestId = transactionRequest.id, +// transactionRequestAttributeId = None, +// name = "reject_additional_information", +// attributeType = +// TransactionRequestAttributeType.withName("STRING"), +// value = rejectAdditionalInformation, +// callContext = callContext +// ) +// } else Future.successful(()) +// _ <- NewStyle.function.notifyTransactionRequest( +// fromAccount, +// toAccount, +// transactionRequest, +// callContext +// ) +// _ <- NewStyle.function.saveTransactionRequestStatusImpl( +// transactionRequest.id, +// transactionRequest.status, +// callContext +// ) +// } yield (transactionRequest, callContext) +// case _ => +// // Determine if the current user is answering their own assigned challenge +// val challengeToAnswer = challenges.find(_.challengeId == challengeAnswerJson.id) +// val isAnsweringOwnChallenge = challengeToAnswer.exists(_.expectedUserId == u.userId) +// +// for { +// +// (challengeAnswerIsValidated, callContext) <- if (isAnsweringOwnChallenge) { +// // User is answering their own challenge — validate with userId check +// NewStyle.function.validateChallengeAnswer( +// challengeAnswerJson.id, +// challengeAnswerJson.answer, +// SuppliedAnswerType.PLAIN_TEXT_VALUE, +// callContext +// ) +// } else { +// // User is answering someone else's challenge (checker answering maker's challenge) +// // Safe because maker-checker check already approved this user +// NewStyle.function.validateChallengeAnswerWithoutUserIdCheck( +// challengeAnswerJson.id, +// challengeAnswerJson.answer, +// SuppliedAnswerType.PLAIN_TEXT_VALUE, +// callContext +// ) +// } +// +// _ <- Helper.booleanToFuture( +// s"${InvalidChallengeAnswer +// .replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).") +// .replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")}", +// cc = callContext +// ) { +// challengeAnswerIsValidated +// } +// +// (challengeAnswerIsValidated, callContext) <- NewStyle.function +// .allChallengesSuccessfullyAnswered( +// bankId, +// accountId, +// transReqId, +// callContext +// ) +// _ <- Helper.booleanToFuture( +// s"$NextChallengePending", +// cc = callContext +// ) { +// challengeAnswerIsValidated +// } +// (transactionRequest, callContext) <- TransactionRequestTypes +// .withName(transactionRequestType.value) match { +// case TRANSFER_TO_PHONE | TRANSFER_TO_ATM | +// TRANSFER_TO_ACCOUNT => +// NewStyle.function.createTransactionAfterChallengeV300( +// u, +// fromAccount, +// transReqId, +// transactionRequestType, +// callContext +// ) +// case _ => +// NewStyle.function.createTransactionAfterChallengeV210( +// fromAccount, +// existingTransactionRequest, +// callContext +// ) +// } +// } yield (transactionRequest, callContext) +// } +// +// (transactionRequestAttribute, callContext) <- NewStyle.function +// .getTransactionRequestAttributes( +// bankId, +// transactionRequest.id, +// callContext +// ) +// } yield { +// +// ( +// JSONFactory400.createTransactionRequestWithChargeJSON( +// transactionRequest, +// challenges, +// transactionRequestAttribute +// ), +// HttpCode.`202`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createTransactionRequestAttribute, +// implementedInApiVersion, +// nameOf(createTransactionRequestAttribute), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attribute", +// "Create Transaction Request Attribute", +// s""" Create Transaction Request Attribute +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionRequestAttributeJsonV400, +// transactionRequestAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canCreateTransactionRequestAttributeAtOneBank)) +// ) +// +// lazy val createTransactionRequestAttribute: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transaction-requests" :: TransactionRequestId( +// transactionRequestId +// ) :: "attribute" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $transactionRequestAttributeJsonV400 " +// for { +// (_, callContext) <- NewStyle.function.getTransactionRequestImpl( +// transactionRequestId, +// cc.callContext +// ) +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[TransactionRequestAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" +// transactionRequestAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// TransactionRequestAttributeType.withName(postedData.attribute_type) +// } +// (transactionRequestAttribute, callContext) <- NewStyle.function +// .createOrUpdateTransactionRequestAttribute( +// bankId, +// transactionRequestId, +// None, +// postedData.name, +// transactionRequestAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionRequestAttributeJson( +// transactionRequestAttribute +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionRequestAttributeById, +// implementedInApiVersion, +// nameOf(getTransactionRequestAttributeById), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID", +// "Get Transaction Request Attribute By Id", +// s""" Get Transaction Request Attribute By Id +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionRequestAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canGetTransactionRequestAttributeAtOneBank)) +// ) +// +// lazy val getTransactionRequestAttributeById: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transaction-requests" :: TransactionRequestId( +// transactionRequestId +// ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getTransactionRequestImpl( +// transactionRequestId, +// cc.callContext +// ) +// (transactionRequestAttribute, callContext) <- NewStyle.function +// .getTransactionRequestAttributeById( +// transactionRequestAttributeId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionRequestAttributeJson( +// transactionRequestAttribute +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionRequestAttributes, +// implementedInApiVersion, +// nameOf(getTransactionRequestAttributes), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes", +// "Get Transaction Request Attributes", +// s""" Get Transaction Request Attributes +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionRequestAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canGetTransactionRequestAttributesAtOneBank)) +// ) +// +// lazy val getTransactionRequestAttributes: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transaction-requests" :: TransactionRequestId( +// transactionRequestId +// ) :: "attributes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getTransactionRequestImpl( +// transactionRequestId, +// cc.callContext +// ) +// (transactionRequestAttribute, callContext) <- NewStyle.function +// .getTransactionRequestAttributes( +// bankId, +// transactionRequestId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionRequestAttributesJson( +// transactionRequestAttribute +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateTransactionRequestAttribute, +// implementedInApiVersion, +// nameOf(updateTransactionRequestAttribute), +// "PUT", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transaction-requests/TRANSACTION_REQUEST_ID/attributes/ATTRIBUTE_ID", +// "Update Transaction Request Attribute", +// s""" Update Transaction Request Attribute +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionRequestAttributeJsonV400, +// transactionRequestAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canUpdateTransactionRequestAttributeAtOneBank)) +// ) +// +// lazy val updateTransactionRequestAttribute: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transaction-requests" :: TransactionRequestId( +// transactionRequestId +// ) :: "attributes" :: transactionRequestAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $TransactionRequestAttributeJsonV400" +// for { +// (_, callContext) <- NewStyle.function.getTransactionRequestImpl( +// transactionRequestId, +// cc.callContext +// ) +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[TransactionRequestAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" +// transactionRequestAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// TransactionRequestAttributeType.withName( +// postedData.attribute_type +// ) +// } +// (_, callContext) <- NewStyle.function +// .getTransactionRequestAttributeById( +// transactionRequestAttributeId, +// callContext +// ) +// (transactionRequestAttribute, callContext) <- NewStyle.function +// .createOrUpdateTransactionRequestAttribute( +// bankId, +// transactionRequestId, +// Some(transactionRequestAttributeId), +// postedData.name, +// transactionRequestAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionRequestAttributeJson( +// transactionRequestAttribute +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateTransactionRequestAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateTransactionRequestAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/transaction-request", +// "Create or Update Transaction Request Attribute Definition", +// s""" Create or Update Transaction Request Attribute Definition +// | +// |The category field must be ${AttributeCategory.TransactionRequest} +// | +// |The type field must be one of: ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionRequestAttributeDefinitionJsonV400, +// transactionRequestAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canCreateTransactionRequestAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateTransactionRequestAttributeDefinition +// : OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER}(123) and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.TransactionRequest}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionRequestAttributeDefinition, +// implementedInApiVersion, +// nameOf(getTransactionRequestAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/transaction-request", +// "Get Transaction Request Attribute Definition", +// s""" Get Transaction Request Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionRequestAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canGetTransactionRequestAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getTransactionRequestAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "transaction-request" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName( +// AttributeCategory.TransactionRequest.toString +// ), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson( +// attributeDefinitions +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteTransactionRequestAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteTransactionRequestAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction-request", +// "Delete Transaction Request Attribute Definition", +// s""" Delete Transaction Request Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), +// Some(List(canDeleteTransactionRequestAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteTransactionRequestAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction-request" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName( +// AttributeCategory.TransactionRequest.toString +// ), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getSystemDynamicEntities, +// implementedInApiVersion, +// nameOf(getSystemDynamicEntities), +// "GET", +// "/management/system-dynamic-entities", +// "Get System Dynamic Entities", +// s"""Get all System Dynamic Entities. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )} """, +// EmptyBody, +// ListResult( +// "dynamic_entities", +// List(dynamicEntityResponseBodyExample) +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canGetSystemLevelDynamicEntities)) +// ) +// +// lazy val getSystemDynamicEntities: OBPEndpoint = { +// case "management" :: "system-dynamic-entities" :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicEntities <- Future( +// NewStyle.function.getDynamicEntities(None, false) +// ) +// } yield { +// val listCommons: List[DynamicEntityCommons] = dynamicEntities +// val jObjects = listCommons.map(_.jValue) +// ( +// ListResult("dynamic_entities", jObjects), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelDynamicEntities, +// implementedInApiVersion, +// nameOf(getBankLevelDynamicEntities), +// "GET", +// "/management/banks/BANK_ID/dynamic-entities", +// "Get Bank Level Dynamic Entities", +// s"""Get all the bank level Dynamic Entities for one bank. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )}""", +// EmptyBody, +// ListResult( +// "dynamic_entities", +// List(dynamicEntityResponseBodyExample) +// ), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canGetBankLevelDynamicEntities, canGetAnyBankLevelDynamicEntities)) +// ) +// +// lazy val getBankLevelDynamicEntities: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-entities" :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicEntities <- Future( +// NewStyle.function.getDynamicEntities(Some(bankId), false) +// ) +// } yield { +// val listCommons: List[DynamicEntityCommons] = dynamicEntities +// val jObjects = listCommons.map(_.jValue) +// ( +// ListResult("dynamic_entities", jObjects), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// private def createDynamicEntityMethod( +// cc: CallContext, +// dynamicEntity: DynamicEntityCommons +// ) = { +// for { +// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( +// dynamicEntity, +// cc.callContext +// ) +// // granted the CRUD roles to the loggedIn User +// curdRoles = List( +// DynamicEntityInfo +// .canCreateRole(result.entityName, dynamicEntity.bankId), +// DynamicEntityInfo +// .canUpdateRole(result.entityName, dynamicEntity.bankId), +// DynamicEntityInfo.canGetRole(result.entityName, dynamicEntity.bankId), +// DynamicEntityInfo.canDeleteRole( +// result.entityName, +// dynamicEntity.bankId +// ) +// ) +// } yield { +// curdRoles.map(role => +// Entitlement.entitlement.vend.addEntitlement( +// dynamicEntity.bankId.getOrElse(""), +// cc.userId, +// role.toString() +// ) +// ) +// val commonsData: DynamicEntityCommons = result +// (commonsData.jValue, HttpCode.`201`(cc.callContext)) +// } +// } +// +// private def createDynamicEntityDoc = ResourceDoc( +// createSystemDynamicEntity, +// implementedInApiVersion, +// nameOf(createSystemDynamicEntity), +// "POST", +// "/management/system-dynamic-entities", +// "Create System Level Dynamic Entity", +// s"""Create a system level Dynamic Entity. +// | +// |Note: To see DynamicEntity in API Explorer II, find OBPdynamic-entity or similar in the list of API versions. +// | +// |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints. +// | +// |**Discovering the generated endpoints:** +// | +// |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use: +// | +// |`GET /resource-docs/API_VERSION/obp?content=dynamic` +// | +// |This returns documentation for all dynamic endpoints including paths, schemas, and required roles. +// | +// |For more information about Dynamic Entities see ${Glossary +// .getGlossaryItemLink("Dynamic-Entities")} +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically +// | +// |The following field types are as supported: +// |${DynamicEntityFieldType.values +// .map(_.toString) +// .mkString("[", ", ", ", reference]")} +// | +// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} +// | +// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. +// | +// |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity. +// | +// |To see the complete list of available reference types and their correct formats, call: +// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** +// | +// |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format. +// | +// |**The hasPersonalEntity flag:** +// | +// |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints. +// |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records. +// | +// |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences. +// | +// |$dynamicEntityNamingExplanation +// | +// |**Example Request Body 1:** +// |```json +// |{ +// | "AgentConversation": { +// | "description": "Stores conversation metadata between users and agents", +// | "required": ["conversation_id", "user_id"], +// | "properties": { +// | "conversation_id": { +// | "type": "string", +// | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1" +// | }, +// | "user_id": { +// | "type": "string", +// | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a" +// | }, +// | "title": { +// | "type": "string", +// | "example": "Stripe price ID error" +// | }, +// | "created_at": { +// | "type": "string", +// | "example": "2025-01-07T14:30:00.000Z" +// | }, +// | "model": { +// | "type": "string", +// | "example": "gpt-5" +// | }, +// | "language": { +// | "type": "string", +// | "example": "en" +// | }, +// | "metadata_platform": { +// | "type": "string", +// | "example": "web" +// | }, +// | "metadata_browser": { +// | "type": "string", +// | "example": "Firefox 144.0" +// | }, +// | "metadata_os": { +// | "type": "string", +// | "example": "Ubuntu 22.04" +// | }, +// | "tags": { +// | "type": "string", +// | "example": "stripe,api,error" +// | }, +// | "summary": { +// | "type": "string", +// | "example": "User received 'No such price' error using Stripe API" +// | }, +// | "custom_metadata": { +// | "type": "json", +// | "example": { +// | "priority": "high", +// | "tags": ["support", "billing"], +// | "context": { +// | "page": "checkout", +// | "step": 3 +// | } +// | } +// | } +// | } +// | }, +// | "hasPersonalEntity": true +// |} +// |``` +// | +// | +// |**Example 2: AgentMessage Entity with Reference to the above Entity** +// |```json +// |{ +// | "hasPersonalEntity": true, +// | "AgentMessage": { +// | "description": "Stores individual messages within agent conversations", +// | "required": [ +// | "message_id", +// | "conversation_id", +// | "role" +// | ], +// | "properties": { +// | "message_id": { +// | "type": "string", +// | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002" +// | }, +// | "conversation_id": { +// | "type": "reference:AgentConversation", +// | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388" +// | }, +// | "role": { +// | "type": "string", +// | "example": "user" +// | }, +// | "content_text": { +// | "type": "string", +// | "example": "I'm using Stripe for the first time and getting an error..." +// | }, +// | "timestamp": { +// | "type": "string", +// | "example": "2025-01-07T14:30:15.000Z" +// | }, +// | "token_count": { +// | "type": "integer", +// | "example": 150 +// | }, +// | "model_used": { +// | "type": "string", +// | "example": "gpt-5" +// | } +// | } +// | } +// |} +// |``` +// | +// |$dynamicEntityImportantNotes +// | +// |$dynamicEntityGeneratedTags +// | +// |$dynamicEntityPianoExample +// | +// |**WRONG (will fail validation):** +// |```json +// |{ +// | "entity": { +// | "AgentConversation": { ... } +// | } +// |} +// |``` +// | +// |**CORRECT:** +// |```json +// |{ +// | "AgentConversation": { ... }, +// | "hasPersonalEntity": true +// |} +// |``` +// |""", +// dynamicEntityRequestBodyExample.copy(bankId = None), +// dynamicEntityResponseBodyExample.copy(bankId = None), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canCreateSystemLevelDynamicEntity)) +// ) +// +// lazy val createSystemDynamicEntity: OBPEndpoint = { +// case "management" :: "system-dynamic-entities" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val dynamicEntity = DynamicEntityCommons( +// json.asInstanceOf[JObject], +// None, +// cc.userId, +// None +// ) +// createDynamicEntityMethod(cc, dynamicEntity) +// } +// } +// +// private def createBankLevelDynamicEntityDoc = ResourceDoc( +// createBankLevelDynamicEntity, +// implementedInApiVersion, +// nameOf(createBankLevelDynamicEntity), +// "POST", +// "/management/banks/BANK_ID/dynamic-entities", +// "Create Bank Level Dynamic Entity", +// s"""Create a Bank Level DynamicEntity. +// | +// |Note: Once you have created a DynamicEntity to see it in the API Explorer II, find OBPdynamic-entity or similar in the list of API versions. +// | +// |FYI Dynamic Entities and Dynamic Endpoints are listed in the Resource Doc endpoints by adding content=dynamic to the path. They are cached differently to static endpoints. +// | +// |**Discovering the generated endpoints:** +// | +// |After creating a Dynamic Entity, OBP automatically generates CRUD endpoints. To discover these endpoints programmatically, use: +// | +// |`GET /resource-docs/API_VERSION/obp?content=dynamic` +// | +// |This returns documentation for all dynamic endpoints including paths, schemas, and required roles. +// | +// |For more information about Dynamic Entities see ${Glossary +// .getGlossaryItemLink("Dynamic-Entities")} +// | +// |${userAuthenticationMessage(true)} +// | +// |Create a DynamicEntity. If creation is successful, the corresponding POST, GET, PUT and DELETE (Create, Read, Update, Delete or CRUD for short) endpoints will be generated automatically +// | +// |The following field types are as supported: +// |${DynamicEntityFieldType.values +// .map(_.toString) +// .mkString("[", ", ", ", reference]")} +// | +// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} +// | +// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. +// | +// |Reference types are like foreign keys and composite foreign keys are supported. The value you need to supply as the (composite) foreign key is a UUID (or several UUIDs in the case of a composite key) that match value in another Entity. +// | +// |To see the complete list of available reference types and their correct formats, call: +// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** +// | +// |This endpoint returns all available reference types (both static OBP entities and dynamic entities) with example values showing the correct format. +// | +// |**The hasPersonalEntity flag:** +// | +// |* If `hasPersonalEntity` = **true** (default): OBP generates both regular endpoints AND personal 'my' endpoints. Data is user-scoped - each user only sees their own records via 'my' endpoints. +// |* If `hasPersonalEntity` = **false**: OBP generates ONLY regular endpoints (no 'my' endpoints). Data is shared - all authorized users see the same records. +// | +// |This flag also affects authorization (role-based vs user-scoped) and whether cascade delete is allowed. See the Dynamic-Entities glossary for full details on data storage differences. +// | +// |$dynamicEntityNamingExplanation +// | +// |**Example Request Body 1:** +// |```json +// |{ +// | "AgentConversation": { +// | "description": "Stores conversation metadata between users and agents", +// | "required": ["conversation_id", "user_id"], +// | "properties": { +// | "conversation_id": { +// | "type": "string", +// | "example": "conv_3f8a7b29c91d4a93b0e0f5b1c9a4b2d1" +// | }, +// | "user_id": { +// | "type": "string", +// | "example": "user_47b2de93a3b14f3db6f5aa1e1c892a9a" +// | }, +// | "title": { +// | "type": "string", +// | "example": "Stripe price ID error" +// | }, +// | "created_at": { +// | "type": "string", +// | "example": "2025-01-07T14:30:00.000Z" +// | }, +// | "model": { +// | "type": "string", +// | "example": "gpt-5" +// | }, +// | "language": { +// | "type": "string", +// | "example": "en" +// | }, +// | "metadata_platform": { +// | "type": "string", +// | "example": "web" +// | }, +// | "metadata_browser": { +// | "type": "string", +// | "example": "Firefox 144.0" +// | }, +// | "metadata_os": { +// | "type": "string", +// | "example": "Ubuntu 22.04" +// | }, +// | "tags": { +// | "type": "string", +// | "example": "stripe,api,error" +// | }, +// | "summary": { +// | "type": "string", +// | "example": "User received 'No such price' error using Stripe API" +// | }, +// | "custom_metadata": { +// | "type": "json", +// | "example": { +// | "priority": "high", +// | "tags": ["support", "billing"], +// | "context": { +// | "page": "checkout", +// | "step": 3 +// | } +// | } +// | } +// | } +// | }, +// | "hasPersonalEntity": true +// |} +// |``` +// | +// | +// |**Example 2: AgentMessage Entity with Reference to the above Entity** +// |```json +// |{ +// | "hasPersonalEntity": true, +// | "AgentMessage": { +// | "description": "Stores individual messages within agent conversations", +// | "required": [ +// | "message_id", +// | "conversation_id", +// | "role" +// | ], +// | "properties": { +// | "message_id": { +// | "type": "string", +// | "example": "msg_8a2f3c6c44514c4ea92d4f7b91b6f002" +// | }, +// | "conversation_id": { +// | "type": "reference:AgentConversation", +// | "example": "a8770fca-3d1d-47af-b6d0-7a6c3f124388" +// | }, +// | "role": { +// | "type": "string", +// | "example": "user" +// | }, +// | "content_text": { +// | "type": "string", +// | "example": "I'm using Stripe for the first time and getting an error..." +// | }, +// | "timestamp": { +// | "type": "string", +// | "example": "2025-01-07T14:30:15.000Z" +// | }, +// | "token_count": { +// | "type": "integer", +// | "example": 150 +// | }, +// | "model_used": { +// | "type": "string", +// | "example": "gpt-5" +// | } +// | } +// | } +// |} +// |``` +// | +// |$dynamicEntityImportantNotes +// | +// |$dynamicEntityGeneratedTags +// | +// |$dynamicEntityPianoExample +// | +// |**WRONG (will fail validation):** +// |```json +// |{ +// | "entity": { +// | "AgentConversation": { ... } +// | } +// |} +// |``` +// | +// |**CORRECT:** +// |```json +// |{ +// | "AgentConversation": { ... }, +// | "hasPersonalEntity": true +// |} +// |``` +// |""", +// dynamicEntityRequestBodyExample.copy(bankId = None), +// dynamicEntityResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canCreateBankLevelDynamicEntity, canCreateAnyBankLevelDynamicEntity)) +// ) +// lazy val createBankLevelDynamicEntity: OBPEndpoint = { +// case "management" :: "banks" :: BankId( +// bankId +// ) :: "dynamic-entities" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val dynamicEntity = DynamicEntityCommons( +// json.asInstanceOf[JObject], +// None, +// cc.userId, +// Some(bankId.value) +// ) +// createDynamicEntityMethod(cc, dynamicEntity) +// } +// } +// +// // bankId is option, if it is bankLevelEntity, we need BankId, if system Level Entity, bankId is None. +// private def updateDynamicEntityMethod( +// bankId: Option[String], +// dynamicEntityId: String, +// json: JValue, +// cc: CallContext +// ) = { +// for { +// // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity. +// (entity, _) <- NewStyle.function.getDynamicEntityById( +// bankId, +// dynamicEntityId, +// cc.callContext +// ) +// (box, _) <- NewStyle.function.invokeDynamicConnector( +// GET_ALL, +// entity.entityName, +// None, +// None, +// entity.bankId, +// None, +// None, +// false, +// cc.callContext +// ) +// resultList: JArray = unboxResult( +// box.asInstanceOf[Box[JArray]], +// entity.entityName +// ) +// _ <- Helper.booleanToFuture( +// DynamicEntityOperationNotAllowed, +// cc = cc.callContext +// ) { +// resultList.arr.isEmpty +// } +// +// jsonObject = json.asInstanceOf[JObject] +// dynamicEntity = DynamicEntityCommons( +// jsonObject, +// Some(dynamicEntityId), +// cc.userId, +// bankId +// ) +// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( +// dynamicEntity, +// cc.callContext +// ) +// } yield { +// val commonsData: DynamicEntityCommons = result +// (commonsData.jValue, HttpCode.`200`(cc.callContext)) +// } +// } +// +// private def updateDynamicEntityDoc = ResourceDoc( +// updateSystemDynamicEntity, +// implementedInApiVersion, +// nameOf(updateSystemDynamicEntity), +// "PUT", +// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID", +// "Update System Level Dynamic Entity", +// s"""Update a System Level Dynamic Entity. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )} +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. +// | +// |The following field types are as supported: +// |${DynamicEntityFieldType.values +// .map(_.toString) +// .mkString("[", ", ", ", reference]")} +// | +// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} +// | +// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. +// | +// |To see all available reference types and their correct formats, call: +// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** +// |""", +// dynamicEntityRequestBodyExample.copy(bankId = None), +// dynamicEntityResponseBodyExample.copy(bankId = None), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEntityNotFoundByDynamicEntityId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canUpdateSystemDynamicEntity)) +// ) +// lazy val updateSystemDynamicEntity: OBPEndpoint = { +// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateDynamicEntityMethod(None, dynamicEntityId, json, cc) +// } +// } +// +// private def updateBankLevelDynamicEntityDoc = ResourceDoc( +// updateBankLevelDynamicEntity, +// implementedInApiVersion, +// nameOf(updateBankLevelDynamicEntity), +// "PUT", +// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID", +// "Update Bank Level Dynamic Entity", +// s"""Update a Bank Level DynamicEntity. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )} +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |Update one DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. +// | +// |The following field types are as supported: +// |${DynamicEntityFieldType.values +// .map(_.toString) +// .mkString("[", ", ", ", reference]")} +// | +// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} +// | +// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. +// | +// |To see all available reference types and their correct formats, call: +// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** +// |""", +// dynamicEntityRequestBodyExample.copy(bankId = None), +// dynamicEntityResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canUpdateBankLevelDynamicEntity)) +// ) +// lazy val updateBankLevelDynamicEntity: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateDynamicEntityMethod(Some(bankId), dynamicEntityId, json, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteSystemDynamicEntity, +// implementedInApiVersion, +// nameOf(deleteSystemDynamicEntity), +// "DELETE", +// "/management/system-dynamic-entities/DYNAMIC_ENTITY_ID", +// "Delete System Level Dynamic Entity", +// s"""Delete a DynamicEntity specified by DYNAMIC_ENTITY_ID. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )}/ +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canDeleteSystemLevelDynamicEntity)) +// ) +// lazy val deleteSystemDynamicEntity: OBPEndpoint = { +// case "management" :: "system-dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteDynamicEntityMethod(None, dynamicEntityId, cc) +// } +// } +// +// +// +// private def deleteDynamicEntityMethod( +// bankId: Option[String], +// dynamicEntityId: String, +// cc: CallContext +// ) = { +// for { +// // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity. +// (entity, _) <- NewStyle.function.getDynamicEntityById( +// bankId, +// dynamicEntityId, +// cc.callContext +// ) +// (box, _) <- NewStyle.function.invokeDynamicConnector( +// GET_ALL, +// entity.entityName, +// None, +// None, +// entity.bankId, +// None, +// None, +// false, +// cc.callContext +// ) +// resultList: JArray = unboxResult( +// box.asInstanceOf[Box[JArray]], +// entity.entityName +// ) +// _ <- Helper.booleanToFuture( +// DynamicEntityOperationNotAllowed, +// cc = cc.callContext +// ) { +// resultList.arr.isEmpty +// } +// deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity( +// bankId, +// dynamicEntityId +// ) +// } yield { +// (deleted, HttpCode.`200`(cc.callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelDynamicEntity, +// implementedInApiVersion, +// nameOf(deleteBankLevelDynamicEntity), +// "DELETE", +// "/management/banks/BANK_ID/dynamic-entities/DYNAMIC_ENTITY_ID", +// "Delete Bank Level Dynamic Entity", +// s"""Delete a Bank Level DynamicEntity specified by DYNAMIC_ENTITY_ID. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "Dynamic-Entities" +// )}/ +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi), +// Some(List(canDeleteBankLevelDynamicEntity)) +// ) +// lazy val deleteBankLevelDynamicEntity: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteDynamicEntityMethod(Some(bankId), dynamicEntityId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyDynamicEntities, +// implementedInApiVersion, +// nameOf(getMyDynamicEntities), +// "GET", +// "/my/dynamic-entities", +// "Get My Dynamic Entities", +// s"""Get all my Dynamic Entities (definitions I created). +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "My-Dynamic-Entities" +// )}""", +// EmptyBody, +// ListResult( +// "dynamic_entities", +// List(dynamicEntityResponseBodyExample) +// ), +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi) +// ) +// +// lazy val getMyDynamicEntities: OBPEndpoint = { +// case "my" :: "dynamic-entities" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicEntities <- Future( +// NewStyle.function.getDynamicEntitiesByUserId(cc.userId) +// ) +// } yield { +// val listCommons: List[DynamicEntityCommons] = dynamicEntities +// val jObjects = listCommons.map(_.jValue) +// ( +// ListResult("dynamic_entities", jObjects), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// private def updateMyDynamicEntityDoc = ResourceDoc( +// updateMyDynamicEntity, +// implementedInApiVersion, +// nameOf(updateMyDynamicEntity), +// "PUT", +// "/my/dynamic-entities/DYNAMIC_ENTITY_ID", +// "Update My Dynamic Entity", +// s"""Update my DynamicEntity. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "My-Dynamic-Entities" +// )}/ +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |Update one of my DynamicEntity, after update finished, the corresponding CRUD endpoints will be changed. +// | +// |Current support filed types as follow: +// |${DynamicEntityFieldType.values +// .map(_.toString) +// .mkString("[", ", ", ", reference]")} +// | +// |The ${DynamicEntityFieldType.DATE_WITH_DAY} format is: ${DynamicEntityFieldType.DATE_WITH_DAY.dateFormat} +// | +// |**Important:** Each property MUST include an `example` field with a valid example value. This is required for API documentation and validation. +// | +// |To see all available reference types and their correct formats, call: +// |**GET /obp/v6.0.0/management/dynamic-entities/reference-types** +// |""", +// dynamicEntityRequestBodyExample.copy(bankId = None), +// dynamicEntityResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// DynamicEntityNotFoundByDynamicEntityId, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi) +// ) +// +// lazy val updateMyDynamicEntity: OBPEndpoint = { +// case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicEntities <- Future( +// NewStyle.function.getDynamicEntitiesByUserId(cc.userId) +// ) +// entityOption = dynamicEntities.find( +// _.dynamicEntityId.equals(Some(dynamicEntityId)) +// ) +// myEntity <- NewStyle.function.tryons( +// InvalidMyDynamicEntityUser, +// 400, +// cc.callContext +// ) { +// entityOption.get +// } +// // Check whether there are uploaded data, only if no uploaded data allow to update DynamicEntity. +// (box, _) <- NewStyle.function.invokeDynamicConnector( +// GET_ALL, +// myEntity.entityName, +// None, +// myEntity.dynamicEntityId, +// myEntity.bankId, +// None, +// Some(myEntity.userId), +// false, +// cc.callContext +// ) +// resultList: JArray = unboxResult( +// box.asInstanceOf[Box[JArray]], +// myEntity.entityName +// ) +// _ <- Helper.booleanToFuture( +// DynamicEntityOperationNotAllowed, +// cc = cc.callContext +// ) { +// resultList.arr.isEmpty +// } +// jsonObject = json.asInstanceOf[JObject] +// dynamicEntity = DynamicEntityCommons( +// jsonObject, +// Some(dynamicEntityId), +// cc.userId, +// myEntity.bankId +// ) +// Full(result) <- NewStyle.function.createOrUpdateDynamicEntity( +// dynamicEntity, +// cc.callContext +// ) +// } yield { +// val commonsData: DynamicEntityCommons = result +// (commonsData.jValue, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyDynamicEntity, +// implementedInApiVersion, +// nameOf(deleteMyDynamicEntity), +// "DELETE", +// "/my/dynamic-entities/DYNAMIC_ENTITY_ID", +// "Delete My Dynamic Entity", +// s"""Delete my DynamicEntity specified by DYNAMIC_ENTITY_ID. +// | +// |For more information see ${Glossary.getGlossaryItemLink( +// "My-Dynamic-Entities" +// )} +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagManageDynamicEntity, apiTagApi) +// ) +// +// lazy val deleteMyDynamicEntity: OBPEndpoint = { +// case "my" :: "dynamic-entities" :: dynamicEntityId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicEntities <- Future( +// NewStyle.function.getDynamicEntitiesByUserId(cc.userId) +// ) +// entityOption = dynamicEntities.find( +// _.dynamicEntityId.equals(Some(dynamicEntityId)) +// ) +// myEntity <- NewStyle.function.tryons( +// InvalidMyDynamicEntityUser, +// 400, +// cc.callContext +// ) { +// entityOption.get +// } +// // Check whether there are uploaded data, only if no uploaded data allow to delete DynamicEntity. +// (box, _) <- NewStyle.function.invokeDynamicConnector( +// GET_ALL, +// myEntity.entityName, +// None, +// myEntity.dynamicEntityId, +// myEntity.bankId, +// None, +// Some(myEntity.userId), +// false, +// cc.callContext +// ) +// resultList: JArray = unboxResult( +// box.asInstanceOf[Box[JArray]], +// myEntity.entityName +// ) +// _ <- Helper.booleanToFuture( +// DynamicEntityOperationNotAllowed, +// cc = cc.callContext +// ) { +// resultList.arr.isEmpty +// } +// deleted: Box[Boolean] <- NewStyle.function.deleteDynamicEntity( +// myEntity.bankId, +// dynamicEntityId +// ) +// } yield { +// (deleted, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// private def unboxResult[T: Manifest](box: Box[T], entityName: String): T = { +// if (box.isInstanceOf[Failure]) { +// val failure = box.asInstanceOf[Failure] +// // change the internal db column name 'dynamicdataid' to entity's id name +// val msg = failure.msg.replace( +// DynamicData.DynamicDataId.dbColumnName, +// StringUtils.uncapitalize(entityName) + "Id" +// ) +// val changedMsgFailure = failure.copy(msg = s"$InternalServerError $msg") +// fullBoxOrException[T](changedMsgFailure) +// } +// +// box.openOrThrowException("impossible error") +// } +// +// staticResourceDocs += ResourceDoc( +// resetPasswordUrl, +// implementedInApiVersion, +// nameOf(resetPasswordUrl), +// "POST", +// "/management/user/reset-password-url", +// "Create password reset url", +// s"""Create password reset url. +// | +// |""", +// PostResetPasswordUrlJsonV400( +// "jobloggs", +// "jo@gmail.com", +// "74a8ebcc-10e4-4036-bef3-9835922246bf" +// ), +// ResetPasswordUrlJsonV400( +// "https://apisandbox.openbankproject.com/user_mgt/reset_password/QOL1CPNJPCZ4BRMPX3Z01DPOX1HMGU3L" +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canCreateResetPasswordUrl)) +// ) +// +// lazy val resetPasswordUrl: OBPEndpoint = { +// case "management" :: "user" :: "reset-password-url" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- Helper.booleanToFuture( +// failMsg = ErrorMessages.NotAllowedEndpoint, +// cc = cc.callContext +// ) { +// APIUtil.getPropsAsBoolValue("ResetPasswordUrlEnabled", false) +// } +// failMsg = +// s"$InvalidJsonFormat The Json body should be the ${classOf[PostResetPasswordUrlJsonV400]} " +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[PostResetPasswordUrlJsonV400] +// } +// } yield { +// val resetLink = AuthUser.passwordResetUrl( +// postedData.username, +// postedData.email, +// postedData.user_id +// ) +// ( +// ResetPasswordUrlJsonV400(resetLink), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// addAccount, +// implementedInApiVersion, +// nameOf(addAccount), +// "POST", +// "/banks/BANK_ID/accounts", +// "Create Account (POST)", +// """Create Account at bank specified by BANK_ID. +// | +// |The User can create an Account for themself - or - the User that has the USER_ID specified in the POST body. +// | +// |If the POST body USER_ID *is* specified, the logged in user must have the Role CanCreateAccount. Once created, the Account will be owned by the User specified by USER_ID. +// | +// |If the POST body USER_ID is *not* specified, the account will be owned by the logged in User. +// | +// |The 'product_code' field SHOULD be a product_code from Product. +// |If the product_code matches a product_code from Product, account attributes will be created that match the Product Attributes. +// | +// |Note: The Amount MUST be zero.""".stripMargin, +// createAccountRequestJsonV310, +// createAccountResponseJsonV310, +// List( +// InvalidJsonFormat, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidAccountBalanceAmount, +// InvalidAccountInitialBalance, +// InitialBalanceMustBeZero, +// InvalidAccountBalanceCurrency, +// UnknownError +// ), +// List(apiTagAccount), +// Some(List(canCreateAccount)) +// ).disableAutoValidateRoles() // this means disabled auto roles validation, will manually do the roles validation . +// +// lazy val addAccount: OBPEndpoint = { +// // Create a new account +// case "banks" :: BankId( +// bankId +// ) :: "accounts" :: Nil JsonPost json -> _ => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the ${prettyRender(Extraction.decompose(createAccountRequestJsonV310))} " +// for { +// createAccountJson <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[CreateAccountRequestJsonV310] +// } +// loggedInUserId = cc.userId +// userIdAccountOwner = +// if (createAccountJson.user_id.nonEmpty) createAccountJson.user_id +// else loggedInUserId +// (postedOrLoggedInUser, callContext) <- NewStyle.function +// .findByUserId(userIdAccountOwner, cc.callContext) +// +// _ <- +// if (userIdAccountOwner == loggedInUserId) +// Future.successful(Full(Unit)) +// else +// NewStyle.function.hasEntitlement( +// bankId.value, +// loggedInUserId, +// canCreateAccount, +// callContext, +// s"${UserHasMissingRoles} $canCreateAccount or create account for self" +// ) +// +// initialBalanceAsString = createAccountJson.balance.amount +// // Note: here we map the product_code to account_type +// accountType = createAccountJson.product_code +// accountLabel = createAccountJson.label +// initialBalanceAsNumber <- NewStyle.function.tryons( +// InvalidAccountInitialBalance, +// 400, +// callContext +// ) { +// BigDecimal(initialBalanceAsString) +// } +// _ <- Helper.booleanToFuture( +// InitialBalanceMustBeZero, +// cc = callContext +// ) { 0 == initialBalanceAsNumber } +// _ <- Helper.booleanToFuture( +// InvalidISOCurrencyCode, +// cc = callContext +// ) { +// APIUtil.isValidCurrencyISOCode(createAccountJson.balance.currency) +// } +// currency = createAccountJson.balance.currency +// (_, callContext) <- NewStyle.function.getBank(bankId, callContext) +// _ <- Helper.booleanToFuture( +// s"$InvalidAccountRoutings Duplication detected in account routings, please specify only one value per routing scheme", +// cc = callContext +// ) { +// createAccountJson.account_routings +// .map(_.scheme) +// .distinct +// .size == createAccountJson.account_routings.size +// } +// alreadyExistAccountRoutings <- Future.sequence( +// createAccountJson.account_routings.map(accountRouting => +// NewStyle.function +// .getAccountRouting( +// Some(bankId), +// accountRouting.scheme, +// accountRouting.address, +// callContext +// ) +// .map(_ => Some(accountRouting)) +// .fallbackTo(Future.successful(None)) +// ) +// ) +// alreadyExistingAccountRouting = alreadyExistAccountRoutings +// .collect { case Some(accountRouting) => +// s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}" +// } +// _ <- Helper.booleanToFuture( +// s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})", +// cc = callContext +// ) { +// alreadyExistingAccountRouting.isEmpty +// } +// (bankAccount, callContext) <- NewStyle.function.createBankAccount( +// bankId, +// AccountId(APIUtil.generateUUID()), +// accountType, +// accountLabel, +// currency, +// initialBalanceAsNumber, +// postedOrLoggedInUser.name, +// createAccountJson.branch_id, +// createAccountJson.account_routings.map(r => +// AccountRouting(r.scheme, r.address) +// ), +// callContext +// ) +// accountId = bankAccount.accountId +// (productAttributes, callContext) <- NewStyle.function +// .getProductAttributesByBankAndCode( +// bankId, +// ProductCode(accountType), +// callContext +// ) +// (accountAttributes, callContext) <- NewStyle.function +// .createAccountAttributes( +// bankId, +// accountId, +// ProductCode(accountType), +// productAttributes, +// None, +// callContext: Option[CallContext] +// ) +// // 1 Create or Update the `Owner` for the new account +// // 2 Add permission to the user +// // 3 Set the user as the account holder +// _ <- BankAccountCreation +// .setAccountHolderAndRefreshUserAccountAccess( +// bankId, +// accountId, +// postedOrLoggedInUser, +// callContext +// ) +// } yield { +// ( +// JSONFactory310.createAccountJSON( +// userIdAccountOwner, +// bankAccount, +// accountAttributes +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// root, +// implementedInApiVersion, +// "root", +// "GET", +// "/root", +// "Get API Info (root)", +// """Returns information about: +// | +// |* API version +// |* Hosted by information +// |* Hosted at information +// |* Energy source information +// |* Git Commit""", +// EmptyBody, +// apiInfoJson400, +// List(UnknownError, MandatoryPropertyIsNotSet), +// apiTagApi :: Nil +// ) +// +// lazy val root: OBPEndpoint = { +// case (Nil | "root" :: Nil) JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- Future(()) // Just start async call +// } yield { +// ( +// JSONFactory400.getApiInfoJSON( +// OBPAPI4_0_0.version, +// OBPAPI4_0_0.versionStatus +// ), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCallContext, +// implementedInApiVersion, +// nameOf(getCallContext), +// "GET", +// "/development/call_context", +// "Get the Call Context of a current call", +// s"""Get the Call Context of the current call. +// | +// """.stripMargin, +// EmptyBody, +// EmptyBody, +// List($AuthenticatedUserIsRequired, UnknownError), +// List(apiTagApi), +// Some(List(canGetCallContext)) +// ) +// +// lazy val getCallContext: OBPEndpoint = { +// case "development" :: "call_context" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- Future(()) // Just start async call +// } yield { +// (cc.callContext, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// verifyRequestSignResponse, +// implementedInApiVersion, +// nameOf(verifyRequestSignResponse), +// "GET", +// "/development/echo/jws-verified-request-jws-signed-response", +// "Verify Request and Sign Response of a current call", +// s"""Verify Request and Sign Response of a current call. +// | +// """.stripMargin, +// EmptyBody, +// EmptyBody, +// List($AuthenticatedUserIsRequired, UnknownError), +// List(apiTagApi), +// Some(Nil) +// ) +// +// lazy val verifyRequestSignResponse: OBPEndpoint = { +// case "development" :: "echo" :: "jws-verified-request-jws-signed-response" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- Future(()) // Just start async call +// } yield { +// (cc.callContext, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAccountLabel, +// implementedInApiVersion, +// "updateAccountLabel", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID", +// "Update Account Label", +// s"""Update the label for the account. The label is how the account is known to the account owner e.g. 'My savings account' +// | +// | +// |${userAuthenticationMessage(true)} +// | +// """.stripMargin, +// updateAccountJsonV400, +// successMessage, +// List( +// InvalidJsonFormat, +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError, +// $BankAccountNotFound, +// "user does not have access to owner view on account" +// ), +// List(apiTagAccount) +// ) +// +// lazy val updateAccountLabel: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), account, callContext) <- SS.userAccount +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $InvalidJsonFormat " +// json <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[UpdateAccountJsonV400] +// } +// anyViewContainsCanUpdateBankAccountLabelPermission = Views.views.vend +// .permission(BankIdAccountId(account.bankId, account.accountId), u) +// .map( +// _.views.map( +// _.allowed_actions.exists(_ == CAN_UPDATE_BANK_ACCOUNT_LABEL) +// ) +// ) +// .getOrElse(Nil) +// .find(_.==(true)) +// .getOrElse(false) +// _ <- Helper.booleanToFuture( +// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_UPDATE_BANK_ACCOUNT_LABEL)}` permission on any your views", +// cc = callContext +// ) { +// anyViewContainsCanUpdateBankAccountLabelPermission +// } +// (success, callContext) <- Connector.connector.vend.updateAccountLabel( +// bankId, +// accountId, +// json.label, +// callContext +// ) map { i => +// ( +// unboxFullOrFail( +// i._1, +// i._2, +// s"$UpdateBankAccountLabelError Current BankId is $bankId and Current AccountId is $accountId", +// 404 +// ), +// i._2 +// ) +// } +// } yield { +// (Extraction.decompose(successMessage), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// lockUser, +// implementedInApiVersion, +// nameOf(lockUser), +// "POST", +// "/users/USERNAME/locks", +// "Lock the user", +// s""" +// |Lock a User. +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// EmptyBody, +// userLockStatusJson, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByProviderAndUsername, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canLockUser)) +// ) +// +// lazy val lockUser: OBPEndpoint = { +// case "users" :: username :: "locks" :: Nil JsonPost req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// userLocks <- Future { +// UserLocksProvider.lockUser(localIdentityProvider, username) +// } map { +// unboxFullOrFail( +// _, +// callContext, +// s"$UserNotFoundByProviderAndUsername($username)", +// 404 +// ) +// } +// } yield { +// ( +// JSONFactory400.createUserLockStatusJson(userLocks), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// staticResourceDocs += ResourceDoc( +// createUserWithRoles, +// implementedInApiVersion, +// nameOf(createUserWithRoles), +// "POST", +// "/user-entitlements", +// "Create (DAuth) User with Roles", +// s""" +// |This endpoint is used as part of the DAuth solution to grant Entitlements for Roles to a smart contract on the blockchain. +// | +// |Put the smart contract address in username +// | +// |For provider use "dauth" +// | +// |This endpoint will create the User with username and provider if the User does not already exist. +// | +// |Then it will create Entitlements i.e. grant Roles to the User. +// | +// |Entitlements are used to grant System or Bank level roles to Users. (For Account level privileges, see Views) +// | +// |i.e. Entitlements are used to create / consume system or bank level resources where as views / account access are used to consume / create customer level resources. +// | +// |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":"" +// | +// |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id" +// | +// |Note: The Roles actually granted will depend on the Roles that the calling user has. +// | +// |If you try to grant Entitlements to a user that already exist (duplicate entitilements) you will get an error. +// | +// |For information about DAuth see below: +// | +// |${getGlossaryItem("DAuth")} +// | +// |""", +// postCreateUserWithRolesJsonV400, +// entitlementsJsonV400, +// List( +// AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// IncorrectRoleName, +// EntitlementIsBankRole, +// EntitlementIsSystemRole, +// EntitlementAlreadyExists, +// InvalidUserProvider, +// UnknownError +// ), +// List(apiTagRole, apiTagEntitlement, apiTagUser, apiTagDAuth) +// ) +// +// lazy val createUserWithRoles: OBPEndpoint = { +// case "user-entitlements" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(loggedInUser), callContext) <- authenticatedAccess(cc) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostCreateUserWithRolesJsonV400 " +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[PostCreateUserWithRolesJsonV400] +// } +// +// // provider must start with dauth., can not create other provider users. +// _ <- Helper.booleanToFuture( +// s"$InvalidUserProvider The user.provider must be start with 'dauth.'", +// cc = Some(cc) +// ) { +// postedData.provider.startsWith("dauth.") +// } +// +// // check the system role bankId is Empty, but bank level role need bankId +// _ <- checkRoleBankIdMappings(callContext, postedData) +// +// _ <- checkRolesBankIdExsiting(callContext, postedData) +// +// _ <- checkRolesName(callContext, postedData) +// +// canCreateEntitlementAtAnyBankRole = Entitlement.entitlement.vend +// .getEntitlement( +// "", +// loggedInUser.userId, +// canCreateEntitlementAtAnyBank.toString() +// ) +// +// (targetUser, callContext) <- NewStyle.function +// .getOrCreateResourceUser( +// postedData.provider, +// postedData.username, +// callContext +// ) +// +// _ <- +// if (canCreateEntitlementAtAnyBankRole.isDefined) { +// // If the loggedIn User has `CanCreateEntitlementAtAnyBankRole` role, then we can grant all the requestRoles to the requestUser. +// // But we must check if the requestUser already has the requestRoles or not. +// assertTargetUserLacksRoles( +// targetUser.userId, +// postedData.roles, +// callContext +// ) +// } else { +// // If the loggedIn user does not have the `CanCreateEntitlementAtAnyBankRole` role, we can only grant the roles which the loggedIn user have. +// // So we need to check if the requestRoles are beyond the current loggedIn user has. +// assertUserCanGrantRoles( +// loggedInUser.userId, +// postedData.roles, +// callContext +// ) +// } +// +// addedEntitlements <- addEntitlementsToUser( +// targetUser.userId, +// postedData, +// callContext +// ) +// +// } yield { +// ( +// JSONFactory400.createEntitlementJSONs(addedEntitlements), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getEntitlements, +// implementedInApiVersion, +// "getEntitlements", +// "GET", +// "/users/USER_ID/entitlements", +// "Get Entitlements for User", +// s""" +// | +// | +// """.stripMargin, +// EmptyBody, +// entitlementsJsonV400, +// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError), +// List(apiTagRole, apiTagEntitlement, apiTagUser), +// Some(List(canGetEntitlementsForAnyUserAtAnyBank)) +// ) +// +// lazy val getEntitlements: OBPEndpoint = { +// case "users" :: userId :: "entitlements" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// entitlements <- NewStyle.function.getEntitlementsByUserId( +// userId, +// cc.callContext +// ) +// } yield { +// // Add virtual entitlements for super_admin_user_ids or oidc_operator_user_ids +// val json = if (isSuperAdmin(userId)) { +// JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.superAdminVirtualRoles) +// } else if (isOidcOperator(userId)) { +// JSONFactory200.withVirtualEntitlements(entitlements, JSONFactory200.oidcOperatorVirtualRoles) +// } else { +// JSONFactory200.createEntitlementJSONs(entitlements) +// } +// (json, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getEntitlementsForBank, +// implementedInApiVersion, +// nameOf(getEntitlementsForBank), +// "GET", +// "/banks/BANK_ID/entitlements", +// "Get Entitlements for One Bank", +// s""" +// | +// """.stripMargin, +// EmptyBody, +// entitlementsJsonV400, +// List($AuthenticatedUserIsRequired, UserHasMissingRoles, UnknownError), +// List(apiTagRole, apiTagEntitlement, apiTagUser), +// Some(List(canGetEntitlementsForOneBank, canGetEntitlementsForAnyBank)) +// ) +// +// val allowedEntitlements = +// canGetEntitlementsForOneBank :: canGetEntitlementsForAnyBank :: Nil +// val allowedEntitlementsTxt = allowedEntitlements.mkString(" or ") +// +// lazy val getEntitlementsForBank: OBPEndpoint = { +// case "banks" :: bankId :: "entitlements" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// entitlements <- NewStyle.function.getEntitlementsByBankId( +// bankId, +// cc.callContext +// ) +// } yield { +// val json = JSONFactory400.createEntitlementJSONs(entitlements) +// (json, HttpCode.`200`(cc.callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// addTagForViewOnAccount, +// implementedInApiVersion, +// "addTagForViewOnAccount", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags", +// "Create a tag on account", +// s"""Posts a tag about an account ACCOUNT_ID on a [view](#1_2_1-getViewsForBankAccount) VIEW_ID. +// | +// |${userAuthenticationMessage(true)} +// | +// |Authentication is required as the tag is linked with the user.""", +// postAccountTagJSON, +// accountTagJSON, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// InvalidJsonFormat, +// NoViewPermission, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagAccountMetadata, apiTagAccount) +// ) +// +// lazy val addTagForViewOnAccount: OBPEndpoint = { +// // add a tag +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId( +// viewId +// ) :: "metadata" :: "tags" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = s"$NoViewPermission can_add_tag. Current ViewId($viewId)", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_ADD_TAG) +// } +// tagJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostTransactionTagJSON ", +// 400, +// callContext +// ) { +// json.extract[PostTransactionTagJSON] +// } +// (postedTag, callContext) <- Future( +// Tags.tags.vend.addTagOnAccount(bankId, accountId)( +// u.userPrimaryKey, +// viewId, +// tagJson.value, +// now +// ) +// ) map { i => +// (connectorEmptyResponse(i, callContext), callContext) +// } +// } yield { +// ( +// JSONFactory400.createAccountTagJSON(postedTag), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteTagForViewOnAccount, +// implementedInApiVersion, +// "deleteTagForViewOnAccount", +// "DELETE", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags/TAG_ID", +// "Delete a tag on account", +// s"""Deletes the tag TAG_ID about the account ACCOUNT_ID made on [view](#1_2_1-getViewsForBankAccount). +// | +// |${userAuthenticationMessage(true)} +// | +// |Authentication is required as the tag is linked with the user.""", +// EmptyBody, +// EmptyBody, +// List( +// NoViewPermission, +// ViewNotFound, +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagAccountMetadata, apiTagAccount) +// ) +// +// lazy val deleteTagForViewOnAccount: OBPEndpoint = { +// // delete a tag +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId( +// viewId +// ) :: "metadata" :: "tags" :: tagId :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$NoViewPermission can_delete_tag. Current ViewId($viewId)", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_DELETE_TAG) +// } +// deleted <- Future( +// Tags.tags.vend.deleteTagOnAccount(bankId, accountId)(tagId) +// ) map { i => +// (connectorEmptyResponse(i, callContext), callContext) +// } +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTagsForViewOnAccount, +// implementedInApiVersion, +// "getTagsForViewOnAccount", +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/metadata/tags", +// "Get tags on account", +// s"""Returns the account ACCOUNT_ID tags made on a [view](#1_2_1-getViewsForBankAccount) (VIEW_ID). +// |${userAuthenticationMessage(true)} +// | +// |Authentication is required as the tag is linked with the user.""", +// EmptyBody, +// accountTagsJSON, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// NoViewPermission, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagAccountMetadata, apiTagAccount) +// ) +// +// lazy val getTagsForViewOnAccount: OBPEndpoint = { +// // get tags +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "metadata" :: "tags" :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$NoViewPermission can_see_tags. Current ViewId($viewId)", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_SEE_TAGS) +// } +// tags <- Future( +// Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId) +// ) +// } yield { +// val json = JSONFactory400.createAccountTagsJSON(tags) +// (json, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCoreAccountById, +// implementedInApiVersion, +// nameOf(getCoreAccountById), +// "GET", +// "/my/banks/BANK_ID/accounts/ACCOUNT_ID/account", +// "Get Account by Id (Core)", +// s"""Information returned about the account specified by ACCOUNT_ID: +// | +// |* Number - The human readable account number given by the bank that identifies the account. +// |* Label - A label given by the owner of the account +// |* Owners - Users that own this account +// |* Type - The type of account +// |* Balance - Currency and Value +// |* Account Routings - A list that might include IBAN or national account identifiers +// |* Account Rules - A list that might include Overdraft and other bank specific rules +// |* Tags - A list of Tags assigned to this account +// | +// |This call returns the owner view and requires access to that view. +// | +// | +// |""".stripMargin, +// EmptyBody, +// moderatedCoreAccountJsonV400, +// List($AuthenticatedUserIsRequired, $BankAccountNotFound, UnknownError), +// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil +// ) +// lazy val getCoreAccountById: OBPEndpoint = { +// // get account by id (assume owner view requested) +// case "my" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "account" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), account, callContext) <- SS.userAccount +// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( +// u, +// BankIdAccountId(account.bankId, account.accountId), +// callContext +// ) +// moderatedAccount <- NewStyle.function.moderatedBankAccountCore( +// account, +// view, +// user, +// callContext +// ) +// } yield { +// val availableViews: List[View] = +// Views.views.vend.privateViewsUserCanAccessForAccount( +// u, +// BankIdAccountId(account.bankId, account.accountId) +// ) +// ( +// createNewCoreBankAccountJson(moderatedAccount, availableViews), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getPrivateAccountByIdFull, +// implementedInApiVersion, +// nameOf(getPrivateAccountByIdFull), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account", +// "Get Account by Id (Full)", +// """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID): +// | +// |* Number +// |* Owners +// |* Type +// |* Balance +// |* IBAN +// |* Available views (sorted by short_name) +// | +// |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount). +// | +// |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications. +// |This call provides balance and other account information via delegated authentication using OAuth. +// | +// |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`. +// |""".stripMargin, +// EmptyBody, +// moderatedAccountJSON400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// apiTagAccount :: Nil +// ) +// lazy val getPrivateAccountByIdFull: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// moderatedAccount <- NewStyle.function.moderatedBankAccountCore( +// account, +// view, +// user, +// callContext +// ) +// (accountAttributes, callContext) <- NewStyle.function +// .getAccountAttributesByAccount( +// bankId, +// accountId, +// callContext: Option[CallContext] +// ) +// } yield { +// val availableViews = +// Views.views.vend.privateViewsUserCanAccessForAccount( +// u, +// BankIdAccountId(account.bankId, account.accountId) +// ) +// val viewsAvailable = +// availableViews.map(JSONFactory.createViewJSON).sortBy(_.short_name) +// val tags = Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId) +// ( +// createBankAccountJSON( +// moderatedAccount, +// viewsAvailable, +// accountAttributes, +// tags +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAccountByAccountRouting, +// implementedInApiVersion, +// nameOf(getAccountByAccountRouting), +// "POST", +// "/management/accounts/account-routing-query", +// "Get Account by Account Routing", +// """This endpoint returns the account (if it exists) linked with the provided scheme and address. +// | +// |The `bank_id` field is optional, but if it's not provided, we don't guarantee that the returned account is unique across all the banks. +// | +// |Example of account routing scheme: `IBAN`, "OBP", "AccountNumber", ... +// |Example of account routing address: `DE17500105178275645584`, "321774cc-fccd-11ea-adc1-0242ac120002", "55897106215", ... +// | +// |""".stripMargin, +// bankAccountRoutingJson, +// moderatedAccountJSON400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagAccount) +// ) +// lazy val getAccountByAccountRouting: OBPEndpoint = { +// case "management" :: "accounts" :: "account-routing-query" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121" +// for { +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[BankAccountRoutingJson] +// } +// +// (account, callContext) <- NewStyle.function.getBankAccountByRouting( +// postJson.bank_id.map(BankId(_)), +// postJson.account_routing.scheme, +// postJson.account_routing.address, +// cc.callContext +// ) +// +// user @ Full(u) = cc.user +// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( +// u, +// BankIdAccountId(account.bankId, account.accountId), +// callContext +// ) +// moderatedAccount <- NewStyle.function.moderatedBankAccountCore( +// account, +// view, +// user, +// callContext +// ) +// +// (accountAttributes, callContext) <- NewStyle.function +// .getAccountAttributesByAccount( +// account.bankId, +// account.accountId, +// callContext: Option[CallContext] +// ) +// } yield { +// val availableViews = +// Views.views.vend.privateViewsUserCanAccessForAccount( +// cc.user.openOrThrowException("Exception user"), +// BankIdAccountId(account.bankId, account.accountId) +// ) +// val viewsAvailable = availableViews +// .map(JSONFactory.createViewJSON) +// .sortBy(_.short_name) +// val tags = Tags.tags.vend +// .getTagsOnAccount(account.bankId, account.accountId)(view.viewId) +// ( +// createBankAccountJSON( +// moderatedAccount, +// viewsAvailable, +// accountAttributes, +// tags +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAccountsByAccountRoutingRegex, +// implementedInApiVersion, +// nameOf(getAccountsByAccountRoutingRegex), +// "POST", +// "/management/accounts/account-routing-regex-query", +// "Get Accounts by Account Routing Regex", +// """This endpoint returns an array of accounts matching the provided routing scheme and the routing address regex. +// | +// |The `bank_id` field is optional. +// | +// |Example of account routing scheme: `IBAN`, `OBP`, `AccountNumber`, ... +// |Example of account routing address regex: `DE175.*`, `55897106215-[A-Z]{3}`, ... +// | +// |This endpoint can be used to retrieve multiples accounts matching a same account routing address pattern. +// |For example, if you want to link multiple accounts having different currencies, you can create an account +// |with `123456789-EUR` as Account Number and an other account with `123456789-USD` as Account Number. +// |So we can identify the Account Number as `123456789`, so to get all the accounts with the same account number +// |and the different currencies, we can use this body in the request : +// | +// |``` +// |{ +// | "bank_id": "BANK_ID", +// | "account_routing": { +// | "scheme": "AccountNumber", +// | "address": "123456789-[A-Z]{3}" +// | } +// |} +// |``` +// | +// |This request will returns the accounts matching the routing address regex (`123456789-EUR` and `123456789-USD`). +// | +// |""".stripMargin, +// bankAccountRoutingJson, +// moderatedAccountsJSON400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagAccount) +// ) +// lazy val getAccountsByAccountRoutingRegex: OBPEndpoint = { +// case "management" :: "accounts" :: "account-routing-regex-query" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $accountRoutingJsonV121" +// for { +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[BankAccountRoutingJson] +// } +// +// (accountRoutings, callContext) <- NewStyle.function +// .getAccountRoutingsByScheme( +// postJson.bank_id.map(BankId(_)), +// postJson.account_routing.scheme, +// cc.callContext +// ) +// +// accountRoutingAddressRegex = postJson.account_routing.address.r +// filteredAccountRoutings = accountRoutings.filter(accountRouting => +// accountRoutingAddressRegex +// .findFirstIn(accountRouting.accountRouting.address) +// .isDefined +// ) +// +// user @ Full(u) = cc.user +// +// accountsJson <- Future.sequence( +// filteredAccountRoutings.map(accountRouting => +// for { +// (account, callContext) <- NewStyle.function.getBankAccount( +// accountRouting.bankId, +// accountRouting.accountId, +// callContext +// ) +// view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView( +// u, +// BankIdAccountId(account.bankId, account.accountId), +// callContext +// ) +// moderatedAccount <- NewStyle.function +// .moderatedBankAccountCore(account, view, user, callContext) +// (accountAttributes, callContext) <- NewStyle.function +// .getAccountAttributesByAccount( +// account.bankId, +// account.accountId, +// callContext: Option[CallContext] +// ) +// availableViews = Views.views.vend +// .privateViewsUserCanAccessForAccount( +// cc.user.openOrThrowException("Exception user"), +// BankIdAccountId(account.bankId, account.accountId) +// ) +// viewsAvailable = availableViews +// .map(JSONFactory.createViewJSON) +// .sortBy(_.short_name) +// tags = Tags.tags.vend.getTagsOnAccount( +// account.bankId, +// account.accountId +// )(view.viewId) +// } yield createBankAccountJSON( +// moderatedAccount, +// viewsAvailable, +// accountAttributes, +// tags +// ) +// ) +// ) +// } yield { +// ( +// ModeratedAccountsJSON400(accountsJson), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankAccountsBalancesForCurrentUser, +// implementedInApiVersion, +// nameOf(getBankAccountsBalancesForCurrentUser), +// "GET", +// "/banks/BANK_ID/balances", +// "Get Accounts Balances", +// """Get the Balances for the Accounts of the current User at one bank.""", +// EmptyBody, +// accountBalancesV400Json, +// List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError), +// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil +// ) +// +// lazy val getBankAccountsBalancesForCurrentUser: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "balances" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// (allowedAccounts, callContext) <- BalanceNewStyle +// .getAccountAccessAtBank(u, bankId, callContext) +// (accountsBalances, callContext) <- BalanceNewStyle +// .getBankAccountsBalances(allowedAccounts, callContext) +// } yield { +// (createBalancesJson(accountsBalances), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankAccountBalancesForCurrentUser, +// implementedInApiVersion, +// nameOf(getBankAccountBalancesForCurrentUser), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/balances", +// "Get Account Balances", +// """Get the Balances for one Account of the current User at one bank.""", +// EmptyBody, +// accountBalanceV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// CannotFindAccountAccess, +// UnknownError +// ), +// apiTagAccount :: apiTagPSD2AIS :: apiTagPsd2 :: Nil +// ) +// +// lazy val getBankAccountBalancesForCurrentUser: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "balances" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// (allowedAccounts, callContext) <- BalanceNewStyle +// .getAccountAccessAtBank(u, bankId, callContext) +// msg = s"$CannotFindAccountAccess AccountId(${accountId.value})" +// bankIdAccountId <- NewStyle.function.tryons( +// msg, +// 400, +// cc.callContext +// ) { +// allowedAccounts.find(_.accountId == accountId).get +// } +// (accountBalances, callContext) <- BalanceNewStyle +// .getBankAccountBalances(bankIdAccountId, callContext) +// } yield { +// ( +// createAccountBalancesJson(accountBalances), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getFirehoseAccountsAtOneBank, +// implementedInApiVersion, +// nameOf(getFirehoseAccountsAtOneBank), +// "GET", +// "/banks/BANK_ID/firehose/accounts/views/VIEW_ID", +// "Get Firehose Accounts at Bank", +// s""" +// |Get all Accounts at a Bank. +// | +// |This endpoint allows bulk access to all accounts at the specified bank. +// | +// |Requires the CanUseFirehoseAtAnyBank Role or CanUseAccountFirehose Role +// | +// |Returns all accounts at the bank. The VIEW_ID parameter determines what account data fields are visible according to the view's permissions. +// | +// |The view specified must have is_firehose = true +// | +// |For VIEW_ID try 'owner' or 'firehose' +// | +// |Optional request parameters for filtering by account attributes: +// |URL params example: +// | /banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1 +// | +// |To invalidate browser cache, add timestamp query parameter as follows (the parameter name must be `_timestamp_`): +// |URL params example: +// | `/banks/some-bank-id/firehose/accounts/views/owner?limit=50&offset=1&_timestamp_=1596762180358` +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// EmptyBody, +// moderatedFirehoseAccountsJsonV400, +// List($BankNotFound), +// List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData), +// Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose)) +// ) +// +// lazy val getFirehoseAccountsAtOneBank: OBPEndpoint = { +// // get private accounts for all banks +// case "banks" :: BankId( +// bankId +// ) :: "firehose" :: "accounts" :: "views" :: ViewId( +// viewId +// ) :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), bank, callContext) <- SS.userBank +// _ <- Helper.booleanToFuture( +// failMsg = AccountFirehoseNotAllowedOnThisInstance, +// cc = cc.callContext +// ) { +// allowAccountFirehose +// } +// // here must be a system view, not accountIds in the URL +// view <- ViewNewStyle.checkViewAccessAndReturnView( +// viewId, +// BankIdAccountId(bankId, AccountId("")), +// Some(u), +// callContext +// ) +// availableBankIdAccountIdList <- Future { +// Views.views.vend +// .getAllFirehoseAccounts(bank.bankId) +// .map(a => BankIdAccountId(a.bankId, a.accountId)) +// } +// params = req.params +// .filterNot( +// _._1 == PARAM_TIMESTAMP +// ) // ignore `_timestamp_` parameter, it is for invalid Browser caching +// .filterNot(_._1 == PARAM_LOCALE) +// availableBankIdAccountIdList2 <- +// if (params.isEmpty) { +// Future.successful(availableBankIdAccountIdList) +// } else { +// AccountAttributeX.accountAttributeProvider.vend +// .getAccountIdsByParams(bankId, params) +// .map { boxedAccountIds => +// val accountIds = boxedAccountIds.getOrElse(Nil) +// availableBankIdAccountIdList.filter( +// availableBankIdAccountId => +// accountIds +// .contains(availableBankIdAccountId.accountId.value) +// ) +// } +// } +// moderatedAccounts: List[ModeratedBankAccount] = for { +// // Here is a new for-loop to get the moderated accouts for the firehose user, according to the viewId. +// // 1 each accountId-> find a proper bankAccount object. +// // 2 each bankAccount object find the proper view. +// // 3 use view and user to moderate the bankaccount object. +// bankIdAccountId <- availableBankIdAccountIdList2 +// (bankAccount, callContext) <- Connector.connector.vend +// .getBankAccountLegacy( +// bankIdAccountId.bankId, +// bankIdAccountId.accountId, +// callContext +// ) ?~! s"$BankAccountNotFound Current Bank_Id(${bankIdAccountId.bankId}), Account_Id(${bankIdAccountId.accountId}) " +// moderatedAccount <- bankAccount.moderatedBankAccount( +// view, +// bankIdAccountId, +// Full(u), +// callContext +// ) // Error handling is in lower method +// } yield { +// moderatedAccount +// } +// // if there are accountAttribute query parameter, link to corresponding accountAttributes. +// (accountAttributes: Option[List[AccountAttribute]], callContext) <- +// if (moderatedAccounts.nonEmpty && params.nonEmpty) { +// val futures: List[OBPReturnType[List[AccountAttribute]]] = +// availableBankIdAccountIdList2.map { bankIdAccount => +// val BankIdAccountId(bId, accountId) = bankIdAccount +// NewStyle.function.getAccountAttributesByAccount( +// bId, +// accountId, +// callContext: Option[CallContext] +// ) +// } +// Future.reduceLeft(futures) { (r, t) => // combine to one future +// r.copy(_1 = t._1 ::: t._1) +// } map (it => +// (Some(it._1), it._2) +// ) // convert list to Option[List[AccountAttribute]] +// } else { +// Future.successful(None, callContext) +// } +// } yield { +// ( +// JSONFactory400.createFirehoseCoreBankAccountJSON( +// moderatedAccounts, +// accountAttributes +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getFastFirehoseAccountsAtOneBank, +// implementedInApiVersion, +// nameOf(getFastFirehoseAccountsAtOneBank), +// "GET", +// "/management/banks/BANK_ID/fast-firehose/accounts", +// "Get Fast Firehose Accounts at Bank", +// s""" +// | +// |This endpoint allows bulk access to accounts. +// | +// |optional pagination parameters for filter with accounts +// |${urlParametersDocument(true, false)} +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// EmptyBody, +// fastFirehoseAccountsJsonV400, +// List($BankNotFound), +// List(apiTagAccount, apiTagAccountFirehose, apiTagFirehoseData), +// Some(List(canUseAccountFirehoseAtAnyBank, ApiRole.canUseAccountFirehose)) +// ) +// +// lazy val getFastFirehoseAccountsAtOneBank: OBPEndpoint = { +// // get private accounts for all banks +// case "management" :: "banks" :: BankId( +// bankId +// ) :: "fast-firehose" :: "accounts" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), bank, callContext) <- SS.userBank +// _ <- Helper.booleanToFuture( +// failMsg = AccountFirehoseNotAllowedOnThisInstance, +// cc = cc.callContext +// ) { +// allowAccountFirehose +// } +// allowedParams = List("limit", "offset", "sort_direction") +// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) +// (obpQueryParams, callContext) <- NewStyle.function.createObpParams( +// httpParams, +// allowedParams, +// callContext +// ) +// (firehoseAccounts, callContext) <- NewStyle.function +// .getBankAccountsWithAttributes(bankId, obpQueryParams, callContext) +// } yield { +// ( +// JSONFactory400.createFirehoseBankAccountJSON(firehoseAccounts), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomersByCustomerPhoneNumber, +// implementedInApiVersion, +// nameOf(getCustomersByCustomerPhoneNumber), +// "POST", +// "/banks/BANK_ID/search/customers/mobile-phone-number", +// "Get Customers by MOBILE_PHONE_NUMBER", +// s"""Gets the Customers specified by MOBILE_PHONE_NUMBER. +// | +// |There are two wildcards often used in conjunction with the LIKE operator: +// | % - The percent sign represents zero, one, or multiple characters +// | _ - The underscore represents a single character +// |For example {"customer_phone_number":"%381%"} lists all numbers which contain 381 sequence +// | +// |""", +// postCustomerPhoneNumberJsonV400, +// customerJsonV310, +// List( +// $AuthenticatedUserIsRequired, +// UserCustomerLinksNotFoundForUser, +// UnknownError +// ), +// List(apiTagCustomer, apiTagKyc), +// Some(List(canGetCustomersAtOneBank)) +// ) +// +// lazy val getCustomersByCustomerPhoneNumber: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "search" :: "customers" :: "mobile-phone-number" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostCustomerPhoneNumberJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[PostCustomerPhoneNumberJsonV400] +// } +// (customers, callContext) <- NewStyle.function +// .getCustomersByCustomerPhoneNumber( +// bankId, +// postedData.mobile_phone_number, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory300.createCustomersJson(customers), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCurrentUserId, +// implementedInApiVersion, +// nameOf(getCurrentUserId), +// "GET", +// "/users/current/user_id", +// "Get User Id (Current)", +// s"""Get the USER_ID of the logged in user +// | +// |${userAuthenticationMessage(true)} +// """.stripMargin, +// EmptyBody, +// userIdJsonV400, +// List(AuthenticatedUserIsRequired, UnknownError), +// List(apiTagUser) +// ) +// +// lazy val getCurrentUserId: OBPEndpoint = { +// case "users" :: "current" :: "user_id" :: Nil JsonGet _ => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// } yield { +// ( +// JSONFactory400.createUserIdInfoJson(u), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserByUserId, +// implementedInApiVersion, +// nameOf(getUserByUserId), +// "GET", +// "/users/user_id/USER_ID", +// "Get User by USER_ID", +// s"""Get user by USER_ID +// | +// |${userAuthenticationMessage(true)} +// |CanGetAnyUser entitlement is required, +// | +// """.stripMargin, +// EmptyBody, +// userJsonV400, +// List( +// AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UserNotFoundById, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canGetAnyUser)) +// ) +// +// lazy val getUserByUserId: OBPEndpoint = { +// case "users" :: "user_id" :: userId :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// user <- Users.users.vend.getUserByUserIdFuture(userId) map { x => +// unboxFullOrFail( +// x, +// cc.callContext, +// s"$UserNotFoundByUserId Current UserId($userId)" +// ) +// } +// entitlements <- NewStyle.function.getEntitlementsByUserId( +// user.userId, +// cc.callContext +// ) +// acceptMarketingInfo <- NewStyle.function.getAgreementByUserId( +// user.userId, +// "accept_marketing_info", +// cc.callContext +// ) +// termsAndConditions <- NewStyle.function.getAgreementByUserId( +// user.userId, +// "terms_and_conditions", +// cc.callContext +// ) +// privacyConditions <- NewStyle.function.getAgreementByUserId( +// user.userId, +// "privacy_conditions", +// cc.callContext +// ) +// isLocked = LoginAttempt.userIsLocked(user.provider, user.name) +// } yield { +// val agreements = +// acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList +// ( +// JSONFactory400.createUserInfoJSON( +// user, +// entitlements, +// Some(agreements), +// isLocked +// ), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserByUsername, +// implementedInApiVersion, +// nameOf(getUserByUsername), +// "GET", +// "/users/username/USERNAME", +// "Get User by USERNAME", +// s"""Get user by USERNAME +// | +// |${userAuthenticationMessage(true)} +// | +// |CanGetAnyUser entitlement is required, +// | +// """.stripMargin, +// EmptyBody, +// userJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UserNotFoundByProviderAndUsername, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canGetAnyUser)) +// ) +// +// lazy val getUserByUsername: OBPEndpoint = { +// case "users" :: "username" :: username :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// user <- Users.users.vend.getUserByProviderAndUsernameFuture( +// Constant.localIdentityProvider, +// username +// ) map { x => +// unboxFullOrFail( +// x, +// cc.callContext, +// UserNotFoundByProviderAndUsername, +// 404 +// ) +// } +// entitlements <- NewStyle.function.getEntitlementsByUserId( +// user.userId, +// cc.callContext +// ) +// isLocked = LoginAttempt.userIsLocked(user.provider, user.name) +// } yield { +// ( +// JSONFactory400.createUserInfoJSON( +// user, +// entitlements, +// None, +// isLocked +// ), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUsersByEmail, +// implementedInApiVersion, +// nameOf(getUsersByEmail), +// "GET", +// "/users/email/USER_EMAIL/terminator", +// "Get Users by Email Address", +// s"""Get users by email address +// | +// |${userAuthenticationMessage(true)} +// |CanGetAnyUser entitlement is required, +// | +// """.stripMargin, +// EmptyBody, +// usersJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UserNotFoundByEmail, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canGetAnyUser)) +// ) +// +// lazy val getUsersByEmail: OBPEndpoint = { +// case "users" :: "email" :: email :: "terminator" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// users <- Users.users.vend.getUsersByEmail(email) +// } yield { +// ( +// JSONFactory400.createUsersJson(users), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUsers, +// implementedInApiVersion, +// nameOf(getUsers), +// "GET", +// "/users", +// "Get all Users", +// s"""Get all users +// | +// |${userAuthenticationMessage(true)} +// | +// |CanGetAnyUser entitlement is required, +// | +// |${urlParametersDocument(false, false)} +// |* locked_status (if null ignore) +// | +// """.stripMargin, +// EmptyBody, +// usersJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canGetAnyUser)) +// ) +// +// lazy val getUsers: OBPEndpoint = { +// case "users" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url) +// (obpQueryParams, callContext) <- createQueriesByHttpParamsFuture( +// httpParams, +// cc.callContext +// ) +// users <- Users.users.vend.getUsers(obpQueryParams) +// } yield { +// (JSONFactory400.createUsersJson(users), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createUserInvitation, +// implementedInApiVersion, +// nameOf(createUserInvitation), +// "POST", +// "/banks/BANK_ID/user-invitation", +// "Create User Invitation", +// s"""Create User Invitation. +// | +// | This endpoint will send an invitation email to the developers, then they can use the link to create the obp user. +// | +// | purpose filed only support:${UserInvitationPurpose.values +// .toString()}. +// | +// | You can customise the email details use the following webui props: +// | +// | when purpose == ${UserInvitationPurpose.DEVELOPER.toString} +// | webui_developer_user_invitation_email_subject +// | webui_developer_user_invitation_email_from +// | webui_developer_user_invitation_email_text +// | webui_developer_user_invitation_email_html_text +// | +// | when purpose = == ${UserInvitationPurpose.CUSTOMER.toString} +// | webui_customer_user_invitation_email_subject +// | webui_customer_user_invitation_email_from +// | webui_customer_user_invitation_email_text +// | webui_customer_user_invitation_email_html_text +// | +// |""", +// userInvitationPostJsonV400, +// userInvitationJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserCustomerLinksNotFoundForUser, +// UnknownError +// ), +// List(apiTagUserInvitation, apiTagKyc), +// Some(canCreateUserInvitation :: Nil) +// ) +// +// lazy val createUserInvitation: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user-invitation" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// logger.debug(s"Hello from the endpoint {$createUserInvitation}") +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostUserInvitationJsonV400 " +// for { +// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostUserInvitationJsonV400] +// } +// +// _ <- NewStyle.function.tryons( +// s"$InvalidJsonValue postedData.purpose only support ${UserInvitationPurpose.values.toString()}", +// 400, +// cc.callContext +// ) { +// UserInvitationPurpose.withName(postedData.purpose) +// } +// +// (invitation, callContext) <- NewStyle.function.createUserInvitation( +// bankId, +// postedData.first_name, +// postedData.last_name, +// postedData.email, +// postedData.company, +// postedData.country, +// postedData.purpose, +// cc.callContext +// ) +// } yield { +// val link = +// s"${APIUtil.getPropsValue("user_invitation_link_base_URL", APIUtil.getPropsValue("portal_hostname", Constant.HostName))}/user-invitation?id=${invitation.secretKey}" +// if (postedData.purpose == UserInvitationPurpose.DEVELOPER.toString) { +// val subject = getWebUiPropsValue( +// "webui_developer_user_invitation_email_subject", +// "Welcome to the API Playground" +// ) +// val from = getWebUiPropsValue( +// "webui_developer_user_invitation_email_from", +// "do-not-reply@openbankproject.com" +// ) +// val customText = getWebUiPropsValue( +// "webui_developer_user_invitation_email_text", +// DEFAULT_EMAIL_TEXT +// ) +// logger.debug(s"customText: ${customText}") +// val customHtmlText = getWebUiPropsValue( +// "webui_developer_user_invitation_email_html_text", +// DEFAULT_EMAIL_HTML +// ) +// .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName) +// .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link) +// logger.debug(s"customHtmlText: ${customHtmlText}") +// logger.debug( +// s"Before send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}" +// ) +// +// // Use Apache Commons Email wrapper instead of Lift Mailer +// val emailContent = EmailContent( +// from = from, +// to = List(invitation.email), +// subject = subject, +// textContent = Some(customText), +// htmlContent = Some(customHtmlText) +// ) +// +// sendHtmlEmail(emailContent) match { +// case Full(messageId) => +// logger.debug( +// s"Email sent successfully with Message-ID: $messageId" +// ) +// case Empty => logger.error("Failed to send user invitation email") +// } +// +// logger.debug( +// s"After send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}" +// ) +// } else { +// val subject = getWebUiPropsValue( +// "webui_customer_user_invitation_email_subject", +// "Welcome to the API Playground" +// ) +// val from = getWebUiPropsValue( +// "webui_customer_user_invitation_email_from", +// "do-not-reply@openbankproject.com" +// ) +// val customText = getWebUiPropsValue( +// "webui_customer_user_invitation_email_text", +// DEFAULT_EMAIL_TEXT +// ) +// logger.debug(s"customText: ${customText}") +// val customHtmlText = getWebUiPropsValue( +// "webui_customer_user_invitation_email_html_text", +// DEFAULT_EMAIL_HTML +// ) +// .replace(EMAIL_RECIPIENT_PLACEHOLDER, invitation.firstName) +// .replace(ACTIVATE_ACCOUNT_PLACEHOLDER, link) +// logger.debug(s"customHtmlText: ${customHtmlText}") +// logger.debug(s"Before send user invitation by email.") +// +// // Use Apache Commons Email wrapper instead of Lift Mailer +// val emailContent = EmailContent( +// from = from, +// to = List(invitation.email), +// subject = subject, +// textContent = Some(customText), +// htmlContent = Some(customHtmlText) +// ) +// +// sendHtmlEmail(emailContent) match { +// case Full(messageId) => +// logger.debug( +// s"Email sent successfully with Message-ID: $messageId" +// ) +// case Empty => logger.error("Failed to send user invitation email") +// } +// +// logger.debug(s"After send user invitation by email.") +// } +// ( +// JSONFactory400.createUserInvitationJson(invitation), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserInvitationAnonymous, +// implementedInApiVersion, +// nameOf(getUserInvitationAnonymous), +// "POST", +// "/banks/BANK_ID/user-invitations", +// "Get User Invitation Information", +// s"""Get User Invitation Information. +// | +// |${userAuthenticationMessage(false)} +// |""", +// PostUserInvitationAnonymousJsonV400(secret_key = 5819479115482092878L), +// userInvitationJsonV400, +// List( +// $BankNotFound, +// UserCustomerLinksNotFoundForUser, +// CannotGetUserInvitation, +// CannotFindUserInvitation, +// UnknownError +// ), +// List(apiTagUserInvitation, apiTagKyc) +// ) +// +// lazy val getUserInvitationAnonymous: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user-invitations" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostUserInvitationAnonymousJsonV400 " +// for { +// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostUserInvitationAnonymousJsonV400] +// } +// (invitation, callContext) <- NewStyle.function.getUserInvitation( +// bankId, +// postedData.secret_key, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// CannotFindUserInvitation, +// 404, +// cc.callContext +// ) { +// invitation.status == "CREATED" +// } +// _ <- Helper.booleanToFuture( +// CannotFindUserInvitation, +// 404, +// cc.callContext +// ) { +// val validUntil = Calendar.getInstance +// validUntil.setTime(invitation.createdAt.get) +// validUntil.add(Calendar.HOUR, 24) +// validUntil.getTime.after(new Date()) +// } +// } yield { +// ( +// JSONFactory400.createUserInvitationJson(invitation), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserInvitation, +// implementedInApiVersion, +// nameOf(getUserInvitation), +// "GET", +// "/banks/BANK_ID/user-invitations/SECRET_LINK", +// "Get User Invitation", +// s""" Get User Invitation +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// userInvitationJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagUserInvitation), +// Some(List(canGetUserInvitation)) +// ) +// +// lazy val getUserInvitation: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user-invitations" :: secretLink :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (invitation, callContext) <- NewStyle.function.getUserInvitation( +// bankId, +// secretLink.toLong, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createUserInvitationJson(invitation), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserInvitations, +// implementedInApiVersion, +// nameOf(getUserInvitations), +// "GET", +// "/banks/BANK_ID/user-invitations", +// "Get User Invitations", +// s""" Get User Invitations +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// userInvitationJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagUserInvitation), +// Some(List(canGetUserInvitation)) +// ) +// +// lazy val getUserInvitations: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "user-invitations" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (invitations, callContext) <- NewStyle.function.getUserInvitations( +// bankId, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createUserInvitationJson(invitations), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteUser, +// implementedInApiVersion, +// nameOf(deleteUser), +// "DELETE", +// "/users/USER_ID", +// "Delete a User", +// s"""Delete a User. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagUser), +// Some(List(canDeleteUser)) +// ) +// +// lazy val deleteUser: OBPEndpoint = { +// case "users" :: userId :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user, callContext) <- NewStyle.function.findByUserId( +// userId, +// cc.callContext +// ) +// (userDeleted, callContext) <- NewStyle.function.deleteUser( +// user.userPrimaryKey, +// callContext +// ) +// } yield { +// (Full(userDeleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// 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 (i.e. when connector=mapped in properties file) +// |The settlement accounts are automatically created by the system when the bank is created. +// |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) +// | +// |""", +// postBankJson400, +// bankJson400, +// List( +// InvalidJsonFormat, +// $AuthenticatedUserIsRequired, +// InsufficientAuthorisationToCreateBank, +// UnknownError +// ), +// List(apiTagBank), +// Some(List(canCreateBank)) +// ) +// +// lazy val createBank: OBPEndpoint = { +// case "banks" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $BankJson400 " +// for { +// bank <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[BankJson400] +// } +// _ <- Helper.booleanToFuture( +// failMsg = ErrorMessages.InvalidConsumerCredentials, +// cc = cc.callContext +// ) { +// cc.callContext.map(_.consumer.isDefined == true).isDefined +// } +// +// checkShortStringValue = APIUtil.checkShortString(bank.id) +// +// _ <- Helper.booleanToFuture( +// failMsg = s"$checkShortStringValue.", +// cc = cc.callContext +// ) { +// checkShortStringValue == SILENCE_IS_GOLDEN +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", +// cc = cc.callContext +// ) { +// bank.id.length > 3 +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidJsonFormat BANK_ID can not contain space characters", +// cc = cc.callContext +// ) { +// !bank.id.contains(" ") +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidJsonFormat BANK_ID can not contain `::::` characters", +// cc = cc.callContext +// ) { +// !`checkIfContains::::`(bank.id) +// } +// +// (success, callContext) <- NewStyle.function.createOrUpdateBank( +// bank.id, +// bank.full_name, +// bank.short_name, +// bank.logo, +// bank.website, +// bank.bank_routings +// .find(_.scheme == "BIC") +// .map(_.address) +// .getOrElse(""), +// "", +// bank.bank_routings +// .filterNot(_.scheme == "BIC") +// .headOption +// .map(_.scheme) +// .getOrElse(""), +// bank.bank_routings +// .filterNot(_.scheme == "BIC") +// .headOption +// .map(_.address) +// .getOrElse(""), +// cc.callContext +// ) +// entitlements <- NewStyle.function.getEntitlementsByUserId( +// cc.userId, +// callContext +// ) +// entitlementsByBank = entitlements.filter(_.bankId == bank.id) +// _ <- entitlementsByBank +// .filter(_.roleName == CanCreateEntitlementAtOneBank.toString()) +// .size > 0 match { +// case true => +// // Already has entitlement +// Future() +// case false => +// Future( +// Entitlement.entitlement.vend.addEntitlement( +// bank.id, +// 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, +// cc.userId, +// CanReadDynamicResourceDocsAtOneBank.toString() +// ) +// ) +// } +// } yield { +// ( +// JSONFactory400.createBankJSON400(success), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createDirectDebit, +// implementedInApiVersion, +// nameOf(createDirectDebit), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/direct-debit", +// "Create Direct Debit", +// s"""Create direct debit for an account. +// | +// |""", +// postDirectDebitJsonV400, +// directDebitJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// NoViewPermission, +// $UserNoPermissionAccessView, +// InvalidJsonFormat, +// CustomerNotFoundByCustomerId, +// UserNotFoundByUserId, +// CounterpartyNotFoundByCounterpartyId, +// UnknownError +// ), +// List(apiTagDirectDebit, apiTagAccount) +// ) +// +// lazy val createDirectDebit: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "direct-debit" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$NoViewPermission can_create_direct_debit. Current ViewId($viewId)", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_CREATE_DIRECT_DEBIT) +// } +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 " +// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[PostDirectDebitJsonV400] +// } +// (_, callContext) <- NewStyle.function.getCustomerByCustomerId( +// postJson.customer_id, +// callContext +// ) +// _ <- Users.users.vend +// .getUserByUserIdFuture(postJson.user_id) map { x => +// unboxFullOrFail( +// x, +// callContext, +// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" +// ) +// } +// (_, callContext) <- NewStyle.function +// .getCounterpartyByCounterpartyId( +// CounterpartyId(postJson.counterparty_id), +// callContext +// ) +// (directDebit, callContext) <- NewStyle.function.createDirectDebit( +// bankId.value, +// accountId.value, +// postJson.customer_id, +// postJson.user_id, +// postJson.counterparty_id, +// if (postJson.date_signed.isDefined) postJson.date_signed.get +// else new Date(), +// postJson.date_starts, +// postJson.date_expires, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createDirectDebitJSON(directDebit), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createDirectDebitManagement, +// implementedInApiVersion, +// nameOf(createDirectDebitManagement), +// "POST", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/direct-debit", +// "Create Direct Debit (management)", +// s"""Create direct debit for an account. +// | +// |""", +// postDirectDebitJsonV400, +// directDebitJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// NoViewPermission, +// InvalidJsonFormat, +// CustomerNotFoundByCustomerId, +// UserNotFoundByUserId, +// CounterpartyNotFoundByCounterpartyId, +// UnknownError +// ), +// List(apiTagDirectDebit, apiTagAccount), +// Some(List(canCreateDirectDebitAtOneBank)) +// ) +// +// lazy val createDirectDebitManagement: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "direct-debit" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostDirectDebitJsonV400 " +// for { +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostDirectDebitJsonV400] +// } +// (_, callContext) <- NewStyle.function.getCustomerByCustomerId( +// postJson.customer_id, +// cc.callContext +// ) +// _ <- Users.users.vend +// .getUserByUserIdFuture(postJson.user_id) map { x => +// unboxFullOrFail( +// x, +// callContext, +// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" +// ) +// } +// (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId( +// CounterpartyId(postJson.counterparty_id), +// callContext +// ) +// (directDebit, callContext) <- NewStyle.function.createDirectDebit( +// bankId.value, +// accountId.value, +// postJson.customer_id, +// postJson.user_id, +// postJson.counterparty_id, +// if (postJson.date_signed.isDefined) postJson.date_signed.get +// else new Date(), +// postJson.date_starts, +// postJson.date_expires, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createDirectDebitJSON(directDebit), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createStandingOrder, +// implementedInApiVersion, +// nameOf(createStandingOrder), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/standing-order", +// "Create Standing Order", +// s"""Create standing order for an account. +// | +// |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’} +// |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}} +// | +// |""", +// postStandingOrderJsonV400, +// standingOrderJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// NoViewPermission, +// InvalidJsonFormat, +// InvalidNumber, +// InvalidISOCurrencyCode, +// CustomerNotFoundByCustomerId, +// UserNotFoundByUserId, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagStandingOrder, apiTagAccount) +// ) +// +// lazy val createStandingOrder: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "standing-order" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$NoViewPermission can_create_standing_order. Current ViewId($viewId)", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_CREATE_STANDING_ORDER) +// } +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 " +// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[PostStandingOrderJsonV400] +// } +// amountValue <- NewStyle.function.tryons( +// s"$InvalidNumber Current input is ${postJson.amount.amount} ", +// 400, +// callContext +// ) { +// BigDecimal(postJson.amount.amount) +// } +// _ <- Helper.booleanToFuture( +// s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'", +// cc = callContext +// ) { +// APIUtil.isValidCurrencyISOCode(postJson.amount.currency) +// } +// (_, callContext) <- NewStyle.function.getCustomerByCustomerId( +// postJson.customer_id, +// callContext +// ) +// _ <- Users.users.vend +// .getUserByUserIdFuture(postJson.user_id) map { x => +// unboxFullOrFail( +// x, +// callContext, +// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" +// ) +// } +// (_, callContext) <- NewStyle.function +// .getCounterpartyByCounterpartyId( +// CounterpartyId(postJson.counterparty_id), +// callContext +// ) +// (directDebit, callContext) <- NewStyle.function.createStandingOrder( +// bankId.value, +// accountId.value, +// postJson.customer_id, +// postJson.user_id, +// postJson.counterparty_id, +// amountValue, +// postJson.amount.currency, +// postJson.when.frequency, +// postJson.when.detail, +// if (postJson.date_signed.isDefined) postJson.date_signed.get +// else new Date(), +// postJson.date_starts, +// postJson.date_expires, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createStandingOrderJSON(directDebit), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createStandingOrderManagement, +// implementedInApiVersion, +// nameOf(createStandingOrderManagement), +// "POST", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/standing-order", +// "Create Standing Order (management)", +// s"""Create standing order for an account. +// | +// |when -> frequency = {‘YEARLY’,’MONTHLY, ‘WEEKLY’, ‘BI-WEEKLY’, DAILY’} +// |when -> detail = { ‘FIRST_MONDAY’, ‘FIRST_DAY’, ‘LAST_DAY’}} +// | +// | +// |""", +// postStandingOrderJsonV400, +// standingOrderJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// NoViewPermission, +// InvalidJsonFormat, +// InvalidNumber, +// InvalidISOCurrencyCode, +// CustomerNotFoundByCustomerId, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagStandingOrder, apiTagAccount), +// Some(List(canCreateStandingOrderAtOneBank)) +// ) +// +// lazy val createStandingOrderManagement: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "standing-order" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostStandingOrderJsonV400 " +// for { +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostStandingOrderJsonV400] +// } +// amountValue <- NewStyle.function.tryons( +// s"$InvalidNumber Current input is ${postJson.amount.amount} ", +// 400, +// cc.callContext +// ) { +// BigDecimal(postJson.amount.amount) +// } +// _ <- Helper.booleanToFuture( +// s"${InvalidISOCurrencyCode} Current input is: '${postJson.amount.currency}'", +// cc = cc.callContext +// ) { +// APIUtil.isValidCurrencyISOCode(postJson.amount.currency) +// } +// (_, callContext) <- NewStyle.function.getCustomerByCustomerId( +// postJson.customer_id, +// cc.callContext +// ) +// _ <- Users.users.vend +// .getUserByUserIdFuture(postJson.user_id) map { x => +// unboxFullOrFail( +// x, +// callContext, +// s"$UserNotFoundByUserId Current UserId(${postJson.user_id})" +// ) +// } +// (_, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId( +// CounterpartyId(postJson.counterparty_id), +// callContext +// ) +// (directDebit, callContext) <- NewStyle.function.createStandingOrder( +// bankId.value, +// accountId.value, +// postJson.customer_id, +// postJson.user_id, +// postJson.counterparty_id, +// amountValue, +// postJson.amount.currency, +// postJson.when.frequency, +// postJson.when.detail, +// if (postJson.date_signed.isDefined) postJson.date_signed.get +// else new Date(), +// postJson.date_starts, +// postJson.date_expires, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createStandingOrderJSON(directDebit), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// grantUserAccessToView, +// implementedInApiVersion, +// "grantUserAccessToView", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/grant", +// "Grant User access to View", +// s"""Grants the User identified by USER_ID access to the view identified by VIEW_ID. +// | +// |${userAuthenticationMessage( +// true +// )} and the user needs to be account holder. +// | +// |""", +// postAccountAccessJsonV400, +// viewJsonV300, +// List( +// $AuthenticatedUserIsRequired, +// UserLacksPermissionCanGrantAccessToViewForTargetAccount, +// InvalidJsonFormat, +// UserNotFoundById, +// SystemViewNotFound, +// ViewNotFound, +// CannotGrantAccountAccess, +// UnknownError +// ), +// List( +// apiTagAccountAccess, +// apiTagView, +// apiTagAccount, +// apiTagUser, +// apiTagOwnerRequired +// ) +// ) +// +// lazy val grantUserAccessToView: OBPEndpoint = { +// // add access for specific user to a specific system view +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "account-access" :: "grant" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " +// for { +// (Full(u), callContext) <- SS.user +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostAccountAccessJsonV400] +// } +// msg = +// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${postJson.view.view_id}) and current UserId(${u.userId})" +// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { +// APIUtil.canGrantAccessToView( +// bankId, +// accountId, +// ViewId(postJson.view.view_id), +// u, +// callContext +// ) +// } +// (user, callContext) <- NewStyle.function.findByUserId( +// postJson.user_id, +// callContext +// ) +// view <- getView(bankId, accountId, postJson.view, callContext) +// addedView <- grantAccountAccessToUser( +// bankId, +// accountId, +// user, +// view, +// callContext +// ) +// } yield { +// val viewJson = JSONFactory300.createViewJSON(addedView) +// (viewJson, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createUserWithAccountAccess, +// implementedInApiVersion, +// nameOf(createUserWithAccountAccess), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/user-account-access", +// "Create (DAuth) User with Account Access", +// s"""This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain. +// | +// |Put the smart contract address in username +// | +// |For provider use "dauth" +// | +// |This endpoint will create the (DAuth) User with username and provider if the User does not already exist. +// | +// |${userAuthenticationMessage( +// true +// )} and the logged in user needs to be account holder. +// | +// |For information about DAuth see below: +// | +// |${getGlossaryItem("DAuth")} +// | +// |""", +// postCreateUserAccountAccessJsonV400, +// List(viewJsonV300), +// List( +// $AuthenticatedUserIsRequired, +// UserLacksPermissionCanGrantAccessToViewForTargetAccount, +// InvalidJsonFormat, +// SystemViewNotFound, +// ViewNotFound, +// CannotGrantAccountAccess, +// UnknownError +// ), +// List( +// apiTagAccountAccess, +// apiTagView, +// apiTagAccount, +// apiTagUser, +// apiTagOwnerRequired, +// apiTagDAuth +// ) +// ) +// +// lazy val createUserWithAccountAccess: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "user-account-access" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostCreateUserAccountAccessJsonV400 " +// for { +// (Full(u), callContext) <- SS.user +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostCreateUserAccountAccessJsonV400] +// } +// // provider must start with dauth., can not create other provider users. +// _ <- Helper.booleanToFuture( +// s"$InvalidUserProvider The user.provider must be start with 'dauth.'", +// cc = Some(cc) +// ) { +// postJson.provider.startsWith("dauth.") +// } +// viewIdList = postJson.views.map(view => ViewId(view.view_id)) +// msg = +// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${viewIdList.mkString}) and current UserId(${u.userId})" +// _ <- Helper.booleanToFuture(msg, 403, cc = Some(cc)) { +// APIUtil.canGrantAccessToMultipleViews( +// bankId, +// accountId, +// viewIdList, +// u, +// callContext +// ) +// } +// (targetUser, callContext) <- NewStyle.function +// .getOrCreateResourceUser( +// postJson.provider, +// postJson.username, +// cc.callContext +// ) +// views <- getViews(bankId, accountId, postJson, callContext) +// addedView <- grantMultpleAccountAccessToUser( +// bankId, +// accountId, +// targetUser, +// views, +// callContext +// ) +// } yield { +// val viewsJson = addedView.map(JSONFactory300.createViewJSON(_)) +// (viewsJson, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// revokeUserAccessToView, +// implementedInApiVersion, +// "revokeUserAccessToView", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access/revoke", +// "Revoke User access to View", +// s"""Revoke the User identified by USER_ID access to the view identified by VIEW_ID. +// | +// |${userAuthenticationMessage( +// true +// )} and the user needs to be account holder. +// | +// |""", +// postAccountAccessJsonV400, +// revokedJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// UserLacksPermissionCanRevokeAccessToViewForTargetAccount, +// InvalidJsonFormat, +// UserNotFoundById, +// SystemViewNotFound, +// ViewNotFound, +// CannotRevokeAccountAccess, +// CannotFindAccountAccess, +// UnknownError +// ), +// List( +// apiTagAccountAccess, +// apiTagView, +// apiTagAccount, +// apiTagUser, +// apiTagOwnerRequired +// ) +// ) +// +// lazy val revokeUserAccessToView: OBPEndpoint = { +// // add access for specific user to a specific system view +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "account-access" :: "revoke" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " +// for { +// (Full(u), callContext) <- SS.user +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostAccountAccessJsonV400] +// } +// viewId = ViewId(postJson.view.view_id) +// msg = +// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${viewId}) and current UserId(${u.userId})" +// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { +// APIUtil.canRevokeAccessToView( +// bankId, +// accountId, +// viewId, +// u, +// callContext +// ) +// } +// (user, callContext) <- NewStyle.function.findByUserId( +// postJson.user_id, +// cc.callContext +// ) +// view <- postJson.view.is_system match { +// case true => ViewNewStyle.systemView(viewId, callContext) +// case false => +// ViewNewStyle.customView( +// viewId, +// BankIdAccountId(bankId, accountId), +// callContext +// ) +// } +// revoked <- postJson.view.is_system match { +// case true => +// ViewNewStyle.revokeAccessToSystemView( +// bankId, +// accountId, +// view, +// user, +// callContext +// ) +// case false => +// ViewNewStyle.revokeAccessToCustomView(view, user, callContext) +// } +// } yield { +// (RevokedJsonV400(revoked), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// revokeGrantUserAccessToViews, +// implementedInApiVersion, +// "revokeGrantUserAccessToViews", +// "PUT", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/account-access", +// "Revoke/Grant User access to View", +// s"""Revoke/Grant the logged in User access to the views identified by json. +// | +// |${userAuthenticationMessage( +// true +// )} and the user needs to be an account holder or has owner view access. +// | +// |""", +// postRevokeGrantAccountAccessJsonV400, +// revokedJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// UserLacksPermissionCanGrantAccessToViewForTargetAccount, +// InvalidJsonFormat, +// UserNotFoundById, +// SystemViewNotFound, +// ViewNotFound, +// CannotRevokeAccountAccess, +// CannotFindAccountAccess, +// UnknownError +// ), +// List( +// apiTagAccountAccess, +// apiTagView, +// apiTagAccount, +// apiTagUser, +// apiTagOwnerRequired +// ) +// ) +// +// lazy val revokeGrantUserAccessToViews: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "account-access" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " +// for { +// (Full(u), callContext) <- SS.user +// postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[PostRevokeGrantAccountAccessJsonV400] +// } +// msg = +// UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${postJson.views.mkString}) and current UserId(${u.userId})" +// _ <- Helper.booleanToFuture(msg, cc = cc.callContext) { +// APIUtil.canRevokeAccessToAllViews(bankId, accountId, u, callContext) +// } +// _ <- Future( +// Views.views.vend +// .revokeAccountAccessByUser(bankId, accountId, u, callContext) +// ) map { +// unboxFullOrFail(_, callContext, s"Cannot revoke") +// } +// grantViews = for (viewId <- postJson.views) +// yield BankIdAccountIdViewId(bankId, accountId, ViewId(viewId)) +// _ <- Future( +// Views.views.vend +// .grantAccessToMultipleViews(grantViews, u, callContext) +// ) map { +// unboxFullOrFail( +// _, +// callContext, +// s"Cannot grant the views: ${postJson.views.mkString(",")}" +// ) +// } +// } yield { +// (RevokedJsonV400(true), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createCustomerAttribute, +// implementedInApiVersion, +// nameOf(createCustomerAttribute), +// "POST", +// "/banks/BANK_ID/customers/CUSTOMER_ID/attribute", +// "Create Customer Attribute", +// s""" Create Customer Attribute +// | +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// customerAttributeJsonV400, +// customerAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some( +// List( +// canCreateCustomerAttributeAtOneBank, +// canCreateCustomerAttributeAtAnyBank +// ) +// ) +// ) +// +// lazy val createCustomerAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "customers" :: customerId :: "attribute" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[CustomerAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)" +// customerAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// CustomerAttributeType.withName(postedData.`type`) +// } +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, cc.callContext) +// _ <- Helper.booleanToFuture( +// InvalidCustomerBankId +// .replaceAll("Bank Id.", s"Bank Id ($bankId).") +// .replaceAll("The Customer", s"The Customer($customerId)"), +// cc = callContext +// ) { customer.bankId == bankId } +// (accountAttribute, callContext) <- NewStyle.function +// .createOrUpdateCustomerAttribute( +// BankId(bankId), +// CustomerId(customerId), +// None, +// postedData.name, +// customerAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerAttributeJson(accountAttribute), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateCustomerAttribute, +// implementedInApiVersion, +// nameOf(updateCustomerAttribute), +// "PUT", +// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID", +// "Update Customer Attribute", +// s""" Update Customer Attribute +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// customerAttributeJsonV400, +// customerAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some( +// List( +// canUpdateCustomerAttributeAtOneBank, +// canUpdateCustomerAttributeAtAnyBank +// ) +// ) +// ) +// +// lazy val updateCustomerAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $CustomerAttributeJsonV400" +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[CustomerAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${CustomerAttributeType.DOUBLE}(12.1234), ${CustomerAttributeType.STRING}(TAX_NUMBER), ${CustomerAttributeType.INTEGER}(123) and ${CustomerAttributeType.DATE_WITH_DAY}(2012-04-23)" +// customerAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// CustomerAttributeType.withName(postedData.`type`) +// } +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, cc.callContext) +// _ <- Helper.booleanToFuture( +// InvalidCustomerBankId +// .replaceAll("Bank Id.", s"Bank Id ($bankId).") +// .replaceAll("The Customer", s"The Customer($customerId)"), +// cc = callContext +// ) { customer.bankId == bankId } +// (accountAttribute, callContext) <- NewStyle.function +// .getCustomerAttributeById( +// customerAttributeId, +// callContext +// ) +// (accountAttribute, callContext) <- NewStyle.function +// .createOrUpdateCustomerAttribute( +// BankId(bankId), +// CustomerId(customerId), +// Some(customerAttributeId), +// postedData.name, +// customerAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerAttributeJson(accountAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomerAttributes, +// implementedInApiVersion, +// nameOf(getCustomerAttributes), +// "GET", +// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes", +// "Get Customer Attributes", +// s""" Get Customer Attributes +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customerAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some( +// List( +// canGetCustomerAttributesAtOneBank, +// canGetCustomerAttributesAtAnyBank +// ) +// ) +// ) +// +// lazy val getCustomerAttributes: OBPEndpoint = { +// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, cc.callContext) +// _ <- Helper.booleanToFuture( +// InvalidCustomerBankId +// .replaceAll("Bank Id.", s"Bank Id ($bankId).") +// .replaceAll("The Customer", s"The Customer($customerId)"), +// cc = callContext +// ) { customer.bankId == bankId } +// (accountAttribute, callContext) <- NewStyle.function +// .getCustomerAttributes( +// BankId(bankId), +// CustomerId(customerId), +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerAttributesJson(accountAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomerAttributeById, +// implementedInApiVersion, +// nameOf(getCustomerAttributeById), +// "GET", +// "/banks/BANK_ID/customers/CUSTOMER_ID/attributes/ATTRIBUTE_ID", +// "Get Customer Attribute By Id", +// s""" Get Customer Attribute By Id +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customerAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some( +// List(canGetCustomerAttributeAtOneBank, canGetCustomerAttributeAtAnyBank) +// ) +// ) +// +// lazy val getCustomerAttributeById: OBPEndpoint = { +// case "banks" :: bankId :: "customers" :: customerId :: "attributes" :: customerAttributeId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, cc.callContext) +// _ <- Helper.booleanToFuture( +// InvalidCustomerBankId +// .replaceAll("Bank Id.", s"Bank Id ($bankId).") +// .replaceAll("The Customer", s"The Customer($customerId)"), +// cc = callContext +// ) { customer.bankId == bankId } +// (accountAttribute, callContext) <- NewStyle.function +// .getCustomerAttributeById( +// customerAttributeId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerAttributeJson(accountAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomersByAttributes, +// implementedInApiVersion, +// nameOf(getCustomersByAttributes), +// "GET", +// "/banks/BANK_ID/customers", +// "Get Customers by ATTRIBUTES", +// s"""Gets the Customers specified by attributes +// | +// |URL params example: /banks/some-bank-id/customers?name=John&age=8 +// |URL params example: /banks/some-bank-id/customers?&limit=50&offset=1 +// | +// | +// |""", +// EmptyBody, +// ListResult( +// "customers", +// List(customerWithAttributesJsonV310) +// ), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserCustomerLinksNotFoundForUser, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canGetCustomersAtOneBank)) +// ) +// +// lazy val getCustomersByAttributes: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "customers" :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (customerIds, callContext) <- NewStyle.function +// .getCustomerIdsByAttributeNameValues(bankId, req.params, Some(cc)) +// list: List[CustomerWithAttributesJsonV310] <- { +// val listCustomerFuture +// : List[Future[CustomerWithAttributesJsonV310]] = +// customerIds.map { customerId => +// val customerFuture = NewStyle.function +// .getCustomerByCustomerId(customerId.value, callContext) +// customerFuture.flatMap { customerAndCc => +// val (customer, cc) = customerAndCc +// NewStyle.function +// .getCustomerAttributes(bankId, customerId, cc) +// .map { attributesAndCc => +// val (attributes, _) = attributesAndCc +// JSONFactory310.createCustomerWithAttributesJson( +// customer, +// attributes +// ) +// } +// } +// } +// Future.sequence(listCustomerFuture) +// } +// } yield { +// (ListResult("customers", list), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createTransactionAttribute, +// implementedInApiVersion, +// nameOf(createTransactionAttribute), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attribute", +// "Create Transaction Attribute", +// s""" Create Transaction Attribute +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionAttributeJsonV400, +// transactionAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canCreateTransactionAttributeAtOneBank)) +// ) +// +// lazy val createTransactionAttribute: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transactions" :: TransactionId( +// transactionId +// ) :: "attribute" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400 " +// for { +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[TransactionAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)" +// transactionAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// TransactionAttributeType.withName(postedData.`type`) +// } +// (accountAttribute, callContext) <- NewStyle.function +// .createOrUpdateTransactionAttribute( +// bankId, +// transactionId, +// None, +// postedData.name, +// transactionAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionAttributeJson(accountAttribute), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateTransactionAttribute, +// implementedInApiVersion, +// nameOf(updateTransactionAttribute), +// "PUT", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ACCOUNT_ATTRIBUTE_ID", +// "Update Transaction Attribute", +// s""" Update Transaction Attribute +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionAttributeJsonV400, +// transactionAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canUpdateTransactionAttributeAtOneBank)) +// ) +// +// lazy val updateTransactionAttribute: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transactions" :: TransactionId( +// transactionId +// ) :: "attributes" :: transactionAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400" +// for { +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[TransactionAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)" +// transactionAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// TransactionAttributeType.withName(postedData.`type`) +// } +// (_, callContext) <- NewStyle.function.getTransactionAttributeById( +// transactionAttributeId, +// callContext +// ) +// (transactionAttribute, callContext) <- NewStyle.function +// .createOrUpdateTransactionAttribute( +// bankId, +// transactionId, +// Some(transactionAttributeId), +// postedData.name, +// transactionAttributeType, +// postedData.value, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionAttributeJson( +// transactionAttribute +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionAttributes, +// implementedInApiVersion, +// nameOf(getTransactionAttributes), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes", +// "Get Transaction Attributes", +// s""" Get Transaction Attributes +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canGetTransactionAttributesAtOneBank)) +// ) +// +// lazy val getTransactionAttributes: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transactions" :: TransactionId( +// transactionId +// ) :: "attributes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// (accountAttribute, callContext) <- NewStyle.function +// .getTransactionAttributes( +// bankId, +// transactionId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionAttributesJson(accountAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionAttributeById, +// implementedInApiVersion, +// nameOf(getTransactionAttributeById), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID/attributes/ATTRIBUTE_ID", +// "Get Transaction Attribute By Id", +// s""" Get Transaction Attribute By Id +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canGetTransactionAttributeAtOneBank)) +// ) +// +// lazy val getTransactionAttributeById: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: "transactions" :: TransactionId( +// transactionId +// ) :: "attributes" :: transactionAttributeId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// (accountAttribute, callContext) <- NewStyle.function +// .getTransactionAttributeById( +// transactionAttributeId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createTransactionAttributeJson(accountAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createHistoricalTransactionAtBank, +// implementedInApiVersion, +// nameOf(createHistoricalTransactionAtBank), +// "POST", +// "/banks/BANK_ID/management/historical/transactions", +// "Create Historical Transactions ", +// s""" +// |Create historical transactions at one Bank +// | +// |Use this endpoint to create transactions between any two accounts at the same bank. +// |From account and to account must be at the same bank. +// |Example: +// |{ +// | "from_account_id": "1ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", +// | "to_account_id": "2ca8a7e4-6d02-48e3-a029-0b2bf89de9f0", +// | "value": { +// | "currency": "GBP", +// | "amount": "10" +// | }, +// | "description": "this is for work", +// | "posted": "2017-09-19T02:31:05Z", +// | "completed": "2017-09-19T02:31:05Z", +// | "type": "SANDBOX_TAN", +// | "charge_policy": "SHARED" +// |} +// | +// |This call is experimental. +// """.stripMargin, +// postHistoricalTransactionAtBankJson, +// postHistoricalTransactionResponseJson, +// List( +// InvalidJsonFormat, +// BankNotFound, +// AccountNotFound, +// CounterpartyNotFoundByCounterpartyId, +// InvalidNumber, +// NotPositiveAmount, +// InvalidTransactionRequestCurrency, +// UnknownError +// ), +// List(apiTagTransactionRequest), +// Some(List(canCreateHistoricalTransactionAtBank)) +// ) +// +// lazy val createHistoricalTransactionAtBank: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "management" :: "historical" :: "transactions" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId.value, +// u.userId, +// ApiRole.canCreateHistoricalTransactionAtBank, +// callContext +// ) +// +// // Check the input JSON format, here is just check the common parts of all four types +// transDetailsJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostHistoricalTransactionJson ", +// 400, +// callContext +// ) { +// json.extract[PostHistoricalTransactionAtBankJson] +// } +// (fromAccount, callContext) <- NewStyle.function +// .checkBankAccountExists( +// bankId, +// AccountId(transDetailsJson.from_account_id), +// callContext +// ) +// (toAccount, callContext) <- NewStyle.function +// .checkBankAccountExists( +// bankId, +// AccountId(transDetailsJson.to_account_id), +// callContext +// ) +// amountNumber <- NewStyle.function.tryons( +// s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", +// 400, +// callContext +// ) { +// BigDecimal(transDetailsJson.value.amount) +// } +// _ <- Helper.booleanToFuture( +// s"${NotPositiveAmount} Current input is: '${amountNumber}'", +// cc = callContext +// ) { +// amountNumber > BigDecimal("0") +// } +// posted <- NewStyle.function.tryons( +// s"$InvalidDateFormat Current `posted` field is ${transDetailsJson.posted}. Please use this format ${DateWithSecondsFormat.toPattern}! ", +// 400, +// callContext +// ) { +// new SimpleDateFormat(DateWithSeconds).parse( +// transDetailsJson.posted +// ) +// } +// completed <- NewStyle.function.tryons( +// s"$InvalidDateFormat Current `completed` field is ${transDetailsJson.completed}. Please use this format ${DateWithSecondsFormat.toPattern}! ", +// 400, +// callContext +// ) { +// new SimpleDateFormat(DateWithSeconds).parse( +// transDetailsJson.completed +// ) +// } +// // Prevent default value for transaction request type (at least). +// _ <- Helper.booleanToFuture( +// s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", +// cc = callContext +// ) { +// APIUtil.isValidCurrencyISOCode(transDetailsJson.value.currency) +// } +// amountOfMoneyJson = AmountOfMoneyJsonV121( +// transDetailsJson.value.currency, +// transDetailsJson.value.amount +// ) +// chargePolicy = transDetailsJson.charge_policy +// // There is no constraint for the type at the moment +// transactionType = transDetailsJson.`type` +// (transactionId, callContext) <- NewStyle.function +// .makeHistoricalPayment( +// fromAccount, +// toAccount, +// posted, +// completed, +// amountNumber, +// transDetailsJson.value.currency, +// transDetailsJson.description, +// transactionType, +// chargePolicy, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createPostHistoricalTransactionResponseJson( +// bankId, +// transactionId, +// fromAccount.accountId, +// toAccount.accountId, +// value = amountOfMoneyJson, +// description = transDetailsJson.description, +// posted, +// completed, +// transactionRequestType = transactionType, +// chargePolicy = transDetailsJson.charge_policy +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionRequest, +// implementedInApiVersion, +// nameOf(getTransactionRequest), +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests/TRANSACTION_REQUEST_ID", +// "Get Transaction Request.", +// """Returns transaction request for transaction specified by TRANSACTION_REQUEST_ID and for account specified by ACCOUNT_ID at bank specified by BANK_ID. +// | +// |The VIEW_ID specified must be 'owner' and the user must have access to this view. +// | +// |Version 2.0.0 now returns charge information. +// | +// |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including: +// | +// |* Transaction Request Id +// |* Type +// |* Status (INITIATED, COMPLETED) +// |* Challenge (in order to confirm the request) +// |* From Bank / Account +// |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.) +// |* Related Transactions +// | +// |PSD2 Context: PSD2 requires transparency of charges to the customer. +// |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after. +// |The customer can proceed with the Transaction by answering the security challenge. +// | +// """.stripMargin, +// EmptyBody, +// transactionRequestWithChargeJSON210, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// GetTransactionRequestsException, +// UnknownError +// ), +// List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2) +// ) +// +// lazy val getTransactionRequest: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "transaction-requests" :: TransactionRequestId( +// requestId +// ) :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- NewStyle.function.isEnabledTransactionRequests(callContext) +// view <- ViewNewStyle.checkAccountAccessAndGetView( +// viewId, +// BankIdAccountId(bankId, accountId), +// Full(u), +// callContext +// ) +// _ <- Helper.booleanToFuture( +// s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${(CAN_SEE_TRANSACTION_REQUESTS)}` permission on the View(${viewId.value})", +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_SEE_TRANSACTION_REQUESTS) +// } +// (transactionRequest, callContext) <- NewStyle.function +// .getTransactionRequestImpl(requestId, callContext) +// } yield { +// val json = JSONFactory210.createTransactionRequestWithChargeJSON( +// transactionRequest +// ) +// (json, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getPrivateAccountsAtOneBank, +// implementedInApiVersion, +// "getPrivateAccountsAtOneBank", +// "GET", +// "/banks/BANK_ID/accounts", +// "Get Accounts at Bank", +// s""" +// |Returns the list of accounts at BANK_ID that the user has access to. +// |For each account the API returns the account ID and the views available to the user.. +// |Each account must have at least one private View. +// | +// |optional request parameters for filter with attributes +// |URL params example: /banks/some-bank-id/accounts?&limit=50&offset=1 +// | +// | +// """.stripMargin, +// EmptyBody, +// basicAccountsJSON, +// List($AuthenticatedUserIsRequired, $BankNotFound, UnknownError), +// List(apiTagAccount, apiTagPrivateData, apiTagPublicData) +// ) +// +// lazy val getPrivateAccountsAtOneBank: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), bank, callContext) <- SS.userBank +// (privateViewsUserCanAccessAtOneBank, privateAccountAccess) = +// Views.views.vend.privateViewsUserCanAccessAtBank(u, bankId) +// params = req.params +// .filterNot( +// _._1 == PARAM_TIMESTAMP +// ) // ignore `_timestamp_` parameter, it is for invalid Browser caching +// .filterNot(_._1 == PARAM_LOCALE) +// privateAccountAccess2 <- +// if (params.isEmpty || privateAccountAccess.isEmpty) { +// Future.successful(privateAccountAccess) +// } else { +// AccountAttributeX.accountAttributeProvider.vend +// .getAccountIdsByParams(bankId, params) +// .map { boxedAccountIds => +// val accountIds = boxedAccountIds.getOrElse(Nil) +// privateAccountAccess.filter(aa => +// accountIds.contains(aa.account_id.get) +// ) +// } +// } +// (availablePrivateAccounts, callContext) <- bank.privateAccountsFuture( +// privateAccountAccess2, +// callContext +// ) +// } yield { +// val bankAccounts = Implementations2_0_0.processAccounts( +// privateViewsUserCanAccessAtOneBank, +// availablePrivateAccounts +// ) +// (bankAccounts, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createConsumer, +// implementedInApiVersion, +// "createConsumer", +// "POST", +// "/management/consumers", +// "Post a Consumer", +// s"""Create a Consumer (Authenticated access). +// | +// |""", +// ConsumerPostJSON( +// "Test", +// "Web", +// "Description", +// "some@email.com", +// "redirecturl", +// "createdby", +// true, +// new Date(), +// """-----BEGIN CERTIFICATE----- +// |client_certificate_content +// |-----END CERTIFICATE-----""".stripMargin +// ), +// consumerJsonV400, +// List( +// AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagConsumer), +// Some(List(canCreateConsumer)) +// ) +// +// lazy val createConsumer: OBPEndpoint = { +// case "management" :: "consumers" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// (postedJson, appType) <- NewStyle.function.tryons( +// InvalidJsonFormat, +// 400, +// callContext +// ) { +// val consumerPostJSON = json.extract[ConsumerPostJSON] +// val appType = +// if (consumerPostJSON.app_type.equals("Confidential")) +// AppType.valueOf("Confidential") +// else AppType.valueOf("Public") +// (consumerPostJSON, appType) +// } +// _ <- NewStyle.function.hasEntitlement( +// "", +// u.userId, +// ApiRole.canCreateConsumer, +// callContext +// ) +// (consumer, callContext) <- createConsumerNewStyle( +// key = Some(Helpers.randomString(40).toLowerCase), +// secret = Some(Helpers.randomString(40).toLowerCase), +// isActive = Some(postedJson.enabled), +// name = Some(postedJson.app_name), +// appType = Some(appType), +// description = Some(postedJson.description), +// developerEmail = Some(postedJson.developer_email), +// company = None, +// redirectURL = Some(postedJson.redirect_url), +// createdByUserId = Some(u.userId), +// clientCertificate = Some(postedJson.clientCertificate), +// logoURL = None, +// callContext +// ) +// user <- Users.users.vend.getUserByUserIdFuture(u.userId) +// } yield { +// // Format the data as json +// val json = JSONFactory400.createConsumerJSON(consumer, user) +// // Return +// (json, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomersAtAnyBank, +// implementedInApiVersion, +// nameOf(getCustomersAtAnyBank), +// "GET", +// "/customers", +// "Get Customers at Any Bank", +// s"""Get Customers at Any Bank. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customersJsonV300, +// List( +// AuthenticatedUserIsRequired, +// UserCustomerLinksNotFoundForUser, +// UnknownError +// ), +// List(apiTagCustomer, apiTagUser), +// Some(List(canGetCustomersAtAllBanks)) +// ) +// lazy val getCustomersAtAnyBank: OBPEndpoint = { +// case "customers" :: Nil JsonGet _ => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (requestParams, callContext) <- extractQueryParams( +// cc.url, +// List("limit", "offset", "sort_direction"), +// cc.callContext +// ) +// (customers, callContext) <- getCustomersAtAllBanks( +// callContext, +// requestParams +// ) +// } yield { +// ( +// JSONFactory300.createCustomersJson(customers.sortBy(_.bankId)), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomersMinimalAtAnyBank, +// implementedInApiVersion, +// nameOf(getCustomersMinimalAtAnyBank), +// "GET", +// "/customers-minimal", +// "Get Customers Minimal at Any Bank", +// s"""Get Customers Minimal at Any Bank. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customersMinimalJsonV300, +// List( +// AuthenticatedUserIsRequired, +// UserCustomerLinksNotFoundForUser, +// UnknownError +// ), +// List(apiTagCustomer, apiTagUser), +// Some(List(canGetCustomersMinimalAtAllBanks)) +// ) +// lazy val getCustomersMinimalAtAnyBank: OBPEndpoint = { +// case "customers-minimal" :: Nil JsonGet _ => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (requestParams, callContext) <- extractQueryParams( +// cc.url, +// List("limit", "offset", "sort_direction"), +// cc.callContext +// ) +// (customers, callContext) <- getCustomersAtAllBanks( +// callContext, +// requestParams +// ) +// } yield { +// ( +// createCustomersMinimalJson(customers.sortBy(_.bankId)), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getScopes, +// implementedInApiVersion, +// nameOf(getScopes), +// "GET", +// "/consumers/CONSUMER_ID/scopes", +// "Get Scopes for Consumer", +// s"""Get all the scopes for an consumer specified by CONSUMER_ID +// | +// |${userAuthenticationMessage(true)} +// | +// | +// """.stripMargin, +// EmptyBody, +// scopeJsons, +// List( +// AuthenticatedUserIsRequired, +// EntitlementNotFound, +// ConsumerNotFoundByConsumerId, +// UnknownError +// ), +// List(apiTagScope, apiTagConsumer) +// ) +// +// lazy val getScopes: OBPEndpoint = { +// case "consumers" :: uuidOfConsumer :: "scopes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// consumer <- Future { callContext.get.consumer } map { x => +// unboxFullOrFail(x, callContext, InvalidConsumerCredentials) +// } +// _ <- Future { +// NewStyle.function.hasEntitlementAndScope( +// "", +// u.userId, +// consumer.id.get.toString, +// canGetEntitlementsForAnyUserAtAnyBank, +// callContext +// ) +// } flatMap { unboxFullAndWrapIntoFuture(_) } +// consumer <- NewStyle.function.getConsumerByConsumerId( +// uuidOfConsumer, +// callContext +// ) +// primaryKeyOfConsumer = consumer.id.get.toString +// scopes <- Future { +// Scope.scope.vend.getScopesByConsumerId(primaryKeyOfConsumer) +// } map { unboxFull(_) } +// } yield ( +// JSONFactory300.createScopeJSONs(scopes), +// HttpCode.`200`(callContext) +// ) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// addScope, +// implementedInApiVersion, +// nameOf(addScope), +// "POST", +// "/consumers/CONSUMER_ID/scopes", +// "Create Scope for a Consumer", +// """Create Scope. Grant Role to Consumer. +// | +// |Scopes are used to grant System or Bank level roles to the Consumer (App). (For Account level privileges, see Views) +// | +// |For a System level Role (.e.g CanGetAnyUser), set bank_id to an empty string i.e. "bank_id":"" +// | +// |For a Bank level Role (e.g. CanCreateAccount), set bank_id to a valid value e.g. "bank_id":"my-bank-id" +// | +// |""", +// SwaggerDefinitionsJSON.createScopeJson, +// scopeJson, +// List( +// AuthenticatedUserIsRequired, +// ConsumerNotFoundById, +// InvalidJsonFormat, +// IncorrectRoleName, +// EntitlementIsBankRole, +// EntitlementIsSystemRole, +// EntitlementAlreadyExists, +// UnknownError +// ), +// List(apiTagScope, apiTagConsumer), +// Some(List(canCreateScopeAtAnyBank, canCreateScopeAtOneBank)) +// ) +// +// lazy val addScope: OBPEndpoint = { +// case "consumers" :: consumerId :: "scopes" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// consumer <- NewStyle.function.getConsumerByConsumerId( +// consumerId, +// callContext +// ) +// postedData <- Future { +// tryo { json.extract[CreateScopeJson] } +// } map { +// val msg = +// s"$InvalidJsonFormat The Json body should be the $CreateScopeJson " +// x => unboxFullOrFail(x, callContext, msg) +// } +// role <- Future { tryo { valueOf(postedData.role_name) } } map { +// val msg = +// IncorrectRoleName + postedData.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted +// .mkString(", ") +// x => unboxFullOrFail(x, callContext, msg) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// if (ApiRole.valueOf(postedData.role_name).requiresBankId) +// EntitlementIsBankRole +// else EntitlementIsSystemRole, +// cc = callContext +// ) { +// ApiRole +// .valueOf(postedData.role_name) +// .requiresBankId == postedData.bank_id.nonEmpty +// } +// allowedEntitlements = +// canCreateScopeAtOneBank :: canCreateScopeAtAnyBank :: Nil +// allowedEntitlementsTxt = +// s"$UserHasMissingRoles ${allowedEntitlements.mkString(", ")}!" +// _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = +// allowedEntitlementsTxt +// )(postedData.bank_id, u.userId, allowedEntitlements, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = BankNotFound, +// cc = callContext +// ) { +// postedData.bank_id.nonEmpty == false || BankX( +// BankId(postedData.bank_id), +// callContext +// ).map(_._1).isEmpty == false +// } +// _ <- Helper.booleanToFuture( +// failMsg = EntitlementAlreadyExists, +// cc = callContext +// ) { +// hasScope(postedData.bank_id, consumerId, role) == false +// } +// addedEntitlement <- Future { +// Scope.scope.vend.addScope( +// postedData.bank_id, +// consumer.id.get.toString, +// postedData.role_name +// ) +// } map { unboxFull(_) } +// } yield { +// ( +// JSONFactory300.createScopeJson(addedEntitlement), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// val customerAttributeGeneralInfo = +// s""" +// |CustomerAttributes are used to enhance the OBP Customer object with Bank specific entities. +// | +// """.stripMargin +// +// staticResourceDocs += ResourceDoc( +// deleteCustomerAttribute, +// implementedInApiVersion, +// nameOf(deleteCustomerAttribute), +// "DELETE", +// "/banks/BANK_ID/CUSTOMER_ID/attributes/CUSTOMER_ATTRIBUTE_ID", +// "Delete Customer Attribute", +// s""" Delete Customer Attribute +// | +// |$customerAttributeGeneralInfo +// | +// |Delete a Customer Attribute by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some( +// List( +// canDeleteCustomerAttributeAtOneBank, +// canDeleteCustomerAttributeAtAnyBank +// ) +// ) +// ) +// +// lazy val deleteCustomerAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "customers" :: "attributes" :: customerAttributeId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (customerAttribute, callContext) <- NewStyle.function +// .deleteCustomerAttribute(customerAttributeId, cc.callContext) +// } yield { +// (Full(customerAttribute), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createDynamicEndpoint, +// implementedInApiVersion, +// nameOf(createDynamicEndpoint), +// "POST", +// "/management/dynamic-endpoints", +// "Create Dynamic Endpoint", +// s"""Create dynamic endpoints. +// | +// |Create dynamic endpoints with one json format swagger content. +// | +// |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields, +// |please check `Endpoint Mapping` endpoints. +// | +// |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n +// |when create MethodRouting for given dynamic endpoint, it will be routed to given url. +// | +// |""", +// dynamicEndpointRequestBodyExample, +// dynamicEndpointResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEndpointExists, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canCreateDynamicEndpoint)) +// ) +// +// lazy val createDynamicEndpoint: OBPEndpoint = { +// case "management" :: "dynamic-endpoints" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// createDynamicEndpointMethod(None, json, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankLevelDynamicEndpoint, +// implementedInApiVersion, +// nameOf(createBankLevelDynamicEndpoint), +// "POST", +// "/management/banks/BANK_ID/dynamic-endpoints", +// "Create Bank Level Dynamic Endpoint", +// s"""Create dynamic endpoints. +// | +// |Create dynamic endpoints with one json format swagger content. +// | +// |If the host of swagger is `dynamic_entity`, then you need link the swagger fields to the dynamic entity fields, +// |please check `Endpoint Mapping` endpoints. +// | +// |If the host of swagger is `obp_mock`, every dynamic endpoint will return example response of swagger,\n +// |when create MethodRouting for given dynamic endpoint, it will be routed to given url. +// | +// |""", +// dynamicEndpointRequestBodyExample, +// dynamicEndpointResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEndpointExists, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canCreateBankLevelDynamicEndpoint, canCreateDynamicEndpoint)) +// ) +// +// lazy val createBankLevelDynamicEndpoint: OBPEndpoint = { +// case "management" :: "banks" :: BankId( +// bankId +// ) :: "dynamic-endpoints" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// createDynamicEndpointMethod(Some(bankId.value), json, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateDynamicEndpointHost, +// implementedInApiVersion, +// nameOf(updateDynamicEndpointHost), +// "PUT", +// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host", +// " Update Dynamic Endpoint Host", +// s"""Update dynamic endpoint Host. +// |The value can be obp_mock, dynamic_entity, or some service url. +// |""", +// dynamicEndpointHostJson400, +// dynamicEndpointHostJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEntityNotFoundByDynamicEntityId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canUpdateDynamicEndpoint)) +// ) +// +// lazy val updateDynamicEndpointHost: OBPEndpoint = { +// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateDynamicEndpointHostMethod(None, dynamicEndpointId, json, cc) +// } +// } +// +// private def updateDynamicEndpointHostMethod( +// bankId: Option[String], +// dynamicEndpointId: String, +// json: JValue, +// cc: CallContext +// ) = { +// for { +// (_, callContext) <- NewStyle.function.getDynamicEndpoint( +// bankId, +// dynamicEndpointId, +// cc.callContext +// ) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $DynamicEndpointHostJson400" +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[DynamicEndpointHostJson400] +// } +// (dynamicEndpoint, callContext) <- NewStyle.function +// .updateDynamicEndpointHost( +// bankId, +// dynamicEndpointId, +// postedData.host, +// cc.callContext +// ) +// } yield { +// (postedData, HttpCode.`201`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankLevelDynamicEndpointHost, +// implementedInApiVersion, +// nameOf(updateBankLevelDynamicEndpointHost), +// "PUT", +// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID/host", +// " Update Bank Level Dynamic Endpoint Host", +// s"""Update Bank Level dynamic endpoint Host. +// |The value can be obp_mock, dynamic_entity, or some service url. +// |""", +// dynamicEndpointHostJson400, +// dynamicEndpointHostJson400, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEntityNotFoundByDynamicEntityId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canUpdateBankLevelDynamicEndpoint, canUpdateDynamicEndpoint)) +// ) +// +// lazy val updateBankLevelDynamicEndpointHost: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: "host" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateDynamicEndpointHostMethod( +// Some(bankId), +// dynamicEndpointId, +// json, +// cc +// ) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getDynamicEndpoint, +// implementedInApiVersion, +// nameOf(getDynamicEndpoint), +// "GET", +// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", +// "Get Dynamic Endpoint", +// s"""Get a Dynamic Endpoint. +// | +// | +// |Get one DynamicEndpoint, +// | +// |""", +// EmptyBody, +// dynamicEndpointResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEndpointNotFoundByDynamicEndpointId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canGetDynamicEndpoint)) +// ) +// +// lazy val getDynamicEndpoint: OBPEndpoint = { +// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getDynamicEndpointMethod(None, dynamicEndpointId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getDynamicEndpoints, +// implementedInApiVersion, +// nameOf(getDynamicEndpoints), +// "GET", +// "/management/dynamic-endpoints", +// " Get Dynamic Endpoints", +// s""" +// | +// |Get Dynamic Endpoints. +// | +// |""", +// EmptyBody, +// ListResult( +// "dynamic_endpoints", +// List(dynamicEndpointResponseBodyExample) +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canGetDynamicEndpoints)) +// ) +// +// lazy val getDynamicEndpoints: OBPEndpoint = { +// case "management" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// getDynamicEndpointsMethod(None, cc) +// } +// } +// +// private def getDynamicEndpointsMethod( +// bankId: Option[String], +// cc: CallContext +// ) = { +// for { +// (dynamicEndpoints, _) <- NewStyle.function.getDynamicEndpoints( +// bankId, +// cc.callContext +// ) +// } yield { +// val resultList = dynamicEndpoints.map[JObject, List[JObject]] { +// dynamicEndpoint => +// val swaggerJson = parse(dynamicEndpoint.swaggerString) +// ( +// "user_id", +// cc.userId +// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) +// } +// ( +// ListResult("dynamic_endpoints", resultList), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelDynamicEndpoint, +// implementedInApiVersion, +// nameOf(getBankLevelDynamicEndpoint), +// "GET", +// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", +// " Get Bank Level Dynamic Endpoint", +// s"""Get a Bank Level Dynamic Endpoint. +// |""", +// EmptyBody, +// dynamicEndpointResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// DynamicEndpointNotFoundByDynamicEndpointId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canGetBankLevelDynamicEndpoint, canGetDynamicEndpoint)) +// ) +// +// lazy val getBankLevelDynamicEndpoint: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonGet req => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc) +// } +// } +// +// private def getDynamicEndpointMethod( +// bankId: Option[String], +// dynamicEndpointId: String, +// cc: CallContext +// ) = { +// for { +// (dynamicEndpoint, callContext) <- NewStyle.function.getDynamicEndpoint( +// bankId, +// dynamicEndpointId, +// cc.callContext +// ) +// } yield { +// val swaggerJson = parse(dynamicEndpoint.swaggerString) +// val responseJson: JObject = ( +// "user_id", +// cc.userId +// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) +// (responseJson, HttpCode.`200`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelDynamicEndpoints, +// implementedInApiVersion, +// nameOf(getBankLevelDynamicEndpoints), +// "GET", +// "/management/banks/BANK_ID/dynamic-endpoints", +// "Get Bank Level Dynamic Endpoints", +// s""" +// | +// |Get Bank Level Dynamic Endpoints. +// | +// |""", +// EmptyBody, +// ListResult( +// "dynamic_endpoints", +// List(dynamicEndpointResponseBodyExample) +// ), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canGetBankLevelDynamicEndpoints, canGetDynamicEndpoints)) +// ) +// +// lazy val getBankLevelDynamicEndpoints: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getDynamicEndpointsMethod(Some(bankId), cc) +// } +// } +// +// private def deleteDynamicEndpointMethod( +// bankId: Option[String], +// dynamicEndpointId: String, +// cc: CallContext +// ) = { +// for { +// deleted <- NewStyle.function.deleteDynamicEndpoint( +// bankId, +// dynamicEndpointId, +// cc.callContext +// ) +// } yield { +// (deleted, HttpCode.`204`(cc.callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteDynamicEndpoint, +// implementedInApiVersion, +// nameOf(deleteDynamicEndpoint), +// "DELETE", +// "/management/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", +// " Delete Dynamic Endpoint", +// s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin, +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// DynamicEndpointNotFoundByDynamicEndpointId, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canDeleteDynamicEndpoint)) +// ) +// +// lazy val deleteDynamicEndpoint: OBPEndpoint = { +// case "management" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteDynamicEndpointMethod(None, dynamicEndpointId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelDynamicEndpoint, +// implementedInApiVersion, +// nameOf(deleteBankLevelDynamicEndpoint), +// "DELETE", +// "/management/banks/BANK_ID/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", +// " Delete Bank Level Dynamic Endpoint", +// s"""Delete a Bank Level DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""".stripMargin, +// EmptyBody, +// EmptyBody, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// DynamicEndpointNotFoundByDynamicEndpointId, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi), +// Some(List(canDeleteBankLevelDynamicEndpoint, canDeleteDynamicEndpoint)) +// ) +// +// lazy val deleteBankLevelDynamicEndpoint: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteDynamicEndpointMethod(Some(bankId), dynamicEndpointId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyDynamicEndpoints, +// implementedInApiVersion, +// nameOf(getMyDynamicEndpoints), +// "GET", +// "/my/dynamic-endpoints", +// "Get My Dynamic Endpoints", +// s"""Get My Dynamic Endpoints.""".stripMargin, +// EmptyBody, +// ListResult( +// "dynamic_endpoints", +// List(dynamicEndpointResponseBodyExample) +// ), +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi) +// ) +// +// lazy val getMyDynamicEndpoints: OBPEndpoint = { +// case "my" :: "dynamic-endpoints" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicEndpoints, _) <- NewStyle.function +// .getDynamicEndpointsByUserId(cc.userId, cc.callContext) +// } yield { +// val resultList = dynamicEndpoints.map[JObject, List[JObject]] { +// dynamicEndpoint => +// val swaggerJson = parse(dynamicEndpoint.swaggerString) +// ( +// "user_id", +// cc.userId +// ) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) +// } +// ( +// ListResult("dynamic_endpoints", resultList), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyDynamicEndpoint, +// implementedInApiVersion, +// nameOf(deleteMyDynamicEndpoint), +// "DELETE", +// "/my/dynamic-endpoints/DYNAMIC_ENDPOINT_ID", +// "Delete My Dynamic Endpoint", +// s"""Delete a DynamicEndpoint specified by DYNAMIC_ENDPOINT_ID.""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// DynamicEndpointNotFoundByDynamicEndpointId, +// UnknownError +// ), +// List(apiTagManageDynamicEndpoint, apiTagApi) +// ) +// +// lazy val deleteMyDynamicEndpoint: OBPEndpoint = { +// case "my" :: "dynamic-endpoints" :: dynamicEndpointId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicEndpoint, callContext) <- NewStyle.function +// .getDynamicEndpoint(None, dynamicEndpointId, cc.callContext) +// _ <- Helper.booleanToFuture( +// InvalidMyDynamicEndpointUser, +// cc = callContext +// ) { +// dynamicEndpoint.userId.equals(cc.userId) +// } +// deleted <- NewStyle.function.deleteDynamicEndpoint( +// None, +// dynamicEndpointId, +// callContext +// ) +// +// } yield { +// (deleted, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateCustomerAttributeAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateCustomerAttributeAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/customer", +// "Create or Update Customer Attribute Definition", +// s""" Create or Update Customer Attribute Definition +// | +// |The category field must be one of: ${AttributeCategory.Customer} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// templateAttributeDefinitionJsonV400, +// templateAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some(List(canCreateCustomerAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateCustomerAttributeAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "customer" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Customer}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateAccountAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateAccountAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/account", +// "Create or Update Account Attribute Definition", +// s""" Create or Update Account Attribute Definition +// | +// |The category field must be ${AttributeCategory.Account} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// accountAttributeDefinitionJsonV400, +// accountAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), +// Some(List(canCreateAccountAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateAccountAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "account" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Account}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateProductAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateProductAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/product", +// "Create or Update Product Attribute Definition", +// s""" Create or Update Product Attribute Definition +// | +// |The category field must be ${AttributeCategory.Product} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// productAttributeDefinitionJsonV400, +// productAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canCreateProductAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateProductAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "product" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Product}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// val productAttributeGeneralInfo = +// s""" +// |Product Attributes are used to describe a financial Product with a list of typed key value pairs. +// | +// |Each Product Attribute is linked to its Product by PRODUCT_CODE +// | +// | +// """.stripMargin +// +// staticResourceDocs += ResourceDoc( +// createProductAttribute, +// implementedInApiVersion, +// nameOf(createProductAttribute), +// "POST", +// "/banks/BANK_ID/products/PRODUCT_CODE/attribute", +// "Create Product Attribute", +// s""" Create Product Attribute +// | +// |$productAttributeGeneralInfo +// | +// |Typical product attributes might be: +// | +// |ISIN (for International bonds) +// |VKN (for German bonds) +// |REDCODE (markit short code for credit derivative) +// |LOAN_ID (e.g. used for Anacredit reporting) +// | +// |ISSUE_DATE (When the bond was issued in the market) +// |MATURITY_DATE (End of life time of a product) +// |TRADABLE +// | +// |See [FPML](http://www.fpml.org/) for more examples. +// | +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// productAttributeJsonV400, +// productAttributeResponseJsonV400, +// List( +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canCreateProductAttribute)) +// ) +// +// lazy val createProductAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "attribute" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId, +// u.userId, +// canCreateProductAttribute, +// callContext +// ) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[ProductAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" +// productAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// ProductAttributeType.withName(postedData.`type`) +// } +// (products, callContext) <- NewStyle.function.getProduct( +// BankId(bankId), +// ProductCode(productCode), +// callContext +// ) +// (productAttribute, callContext) <- NewStyle.function +// .createOrUpdateProductAttribute( +// BankId(bankId), +// ProductCode(productCode), +// None, +// postedData.name, +// productAttributeType, +// postedData.value, +// postedData.is_active, +// callContext: Option[CallContext] +// ) +// } yield { +// ( +// createProductAttributeJson(productAttribute), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateProductAttribute, +// implementedInApiVersion, +// nameOf(updateProductAttribute), +// "PUT", +// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", +// "Update Product Attribute", +// s""" Update Product Attribute. +// | +// +// |$productAttributeGeneralInfo +// | +// |Update one Product Attribute by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// productAttributeJsonV400, +// productAttributeResponseJsonV400, +// List( +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canUpdateProductAttribute)) +// ) +// +// lazy val updateProductAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId, +// u.userId, +// canUpdateProductAttribute, +// callContext +// ) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $ProductAttributeJson " +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[ProductAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${ProductAttributeType.DOUBLE}(12.1234), ${ProductAttributeType.STRING}(TAX_NUMBER), ${ProductAttributeType.INTEGER}(123) and ${ProductAttributeType.DATE_WITH_DAY}(2012-04-23)" +// productAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// ProductAttributeType.withName(postedData.`type`) +// } +// (_, callContext) <- NewStyle.function.getProductAttributeById( +// productAttributeId, +// callContext +// ) +// (productAttribute, callContext) <- NewStyle.function +// .createOrUpdateProductAttribute( +// BankId(bankId), +// ProductCode(productCode), +// Some(productAttributeId), +// postedData.name, +// productAttributeType, +// postedData.value, +// postedData.is_active, +// callContext: Option[CallContext] +// ) +// } yield { +// ( +// createProductAttributeJson(productAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProductAttribute, +// implementedInApiVersion, +// nameOf(getProductAttribute), +// "GET", +// "/banks/BANK_ID/products/PRODUCT_CODE/attributes/PRODUCT_ATTRIBUTE_ID", +// "Get Product Attribute", +// s""" Get Product Attribute +// | +// |$productAttributeGeneralInfo +// | +// |Get one product attribute by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// productAttributeResponseJsonV400, +// List( +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canUpdateProductAttribute)) +// ) +// +// lazy val getProductAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "attributes" :: productAttributeId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId, +// u.userId, +// canGetProductAttribute, +// callContext +// ) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// (productAttribute, callContext) <- NewStyle.function +// .getProductAttributeById(productAttributeId, callContext) +// +// } yield { +// ( +// createProductAttributeJson(productAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createProductFee, +// implementedInApiVersion, +// nameOf(createProductFee), +// "POST", +// "/banks/BANK_ID/products/PRODUCT_CODE/fee", +// "Create Product Fee", +// s"""Create Product Fee +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// productFeeJsonV400.copy(product_fee_id = None), +// productFeeResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagProduct), +// Some(List(canCreateProductFee)) +// ) +// +// lazy val createProductFee: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "fee" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postedData <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ", +// 400, +// Some(cc) +// ) { +// json.extract[ProductFeeJsonV400] +// } +// (_, callContext) <- NewStyle.function.getProduct( +// BankId(bankId), +// ProductCode(productCode), +// Some(cc) +// ) +// (productFee, callContext) <- NewStyle.function +// .createOrUpdateProductFee( +// BankId(bankId), +// ProductCode(productCode), +// None, +// postedData.name, +// postedData.is_active, +// postedData.more_info, +// postedData.value.currency, +// postedData.value.amount, +// postedData.value.frequency, +// postedData.value.`type`, +// callContext: Option[CallContext] +// ) +// } yield { +// (createProductFeeJson(productFee), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateProductFee, +// implementedInApiVersion, +// nameOf(updateProductFee), +// "PUT", +// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", +// "Update Product Fee", +// s""" Update Product Fee. +// | +// |Update one Product Fee by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// productFeeJsonV400.copy(product_fee_id = None), +// productFeeResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct), +// Some(List(canUpdateProductFee)) +// ) +// +// lazy val updateProductFee: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postedData <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $ProductFeeJsonV400 ", +// 400, +// Some(cc) +// ) { +// json.extract[ProductFeeJsonV400] +// } +// (_, callContext) <- NewStyle.function.getProduct( +// BankId(bankId), +// ProductCode(productCode), +// Some(cc) +// ) +// (_, callContext) <- NewStyle.function.getProductFeeById( +// productFeeId, +// callContext +// ) +// (productFee, callContext) <- NewStyle.function +// .createOrUpdateProductFee( +// BankId(bankId), +// ProductCode(productCode), +// Some(productFeeId), +// postedData.name, +// postedData.is_active, +// postedData.more_info, +// postedData.value.currency, +// postedData.value.amount, +// postedData.value.frequency, +// postedData.value.`type`, +// callContext: Option[CallContext] +// ) +// } yield { +// (createProductFeeJson(productFee), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProductFee, +// implementedInApiVersion, +// nameOf(getProductFee), +// "GET", +// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", +// "Get Product Fee", +// s""" Get Product Fee +// | +// |Get one product fee by its id. +// | +// |${userAuthenticationMessage(false)} +// | +// |""", +// EmptyBody, +// productFeeResponseJsonV400, +// List( +// $BankNotFound, +// UnknownError +// ), +// List(apiTagProduct) +// ) +// +// lazy val getProductFee: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- getProductsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// (productFee, callContext) <- NewStyle.function.getProductFeeById( +// productFeeId, +// Some(cc) +// ) +// } yield { +// (createProductFeeJson(productFee), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProductFees, +// implementedInApiVersion, +// nameOf(getProductFees), +// "GET", +// "/banks/BANK_ID/products/PRODUCT_CODE/fees", +// "Get Product Fees", +// s"""Get Product Fees +// | +// |${userAuthenticationMessage(false)} +// | +// |""", +// EmptyBody, +// productFeesResponseJsonV400, +// List( +// $BankNotFound, +// UnknownError +// ), +// List(apiTagProduct) +// ) +// +// lazy val getProductFees: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "fees" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- getProductsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// (productFees, callContext) <- NewStyle.function +// .getProductFeesFromProvider( +// BankId(bankId), +// ProductCode(productCode), +// Some(cc) +// ) +// } yield { +// (createProductFeesJson(productFees), HttpCode.`200`(callContext)) +// } +// } +// } +// staticResourceDocs += ResourceDoc( +// deleteProductFee, +// implementedInApiVersion, +// nameOf(deleteProductFee), +// "DELETE", +// "/banks/BANK_ID/products/PRODUCT_CODE/fees/PRODUCT_FEE_ID", +// "Delete Product Fee", +// s"""Delete Product Fee +// | +// |Delete one product fee by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct), +// Some(List(canDeleteProductFee)) +// ) +// +// lazy val deleteProductFee: OBPEndpoint = { +// case "banks" :: bankId :: "products" :: productCode :: "fees" :: productFeeId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getProductFeeById( +// productFeeId, +// Some(cc) +// ) +// (productFee, callContext) <- NewStyle.function.deleteProductFee( +// productFeeId, +// Some(cc) +// ) +// } yield { +// (productFee, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateBankAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateBankAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/bank", +// "Create or Update Bank Attribute Definition", +// s""" Create or Update Bank Attribute Definition +// | +// |The category field must be ${AttributeCategory.Bank} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// bankAttributeDefinitionJsonV400, +// bankAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute), +// Some(List(canCreateBankAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateBankAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "bank" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Bank}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankAttribute, +// implementedInApiVersion, +// nameOf(createBankAttribute), +// "POST", +// "/banks/BANK_ID/attribute", +// "Create Bank Attribute", +// s""" Create Bank Attribute +// | +// |Typical product attributes might be: +// | +// |ISIN (for International bonds) +// |VKN (for German bonds) +// |REDCODE (markit short code for credit derivative) +// |LOAN_ID (e.g. used for Anacredit reporting) +// | +// |ISSUE_DATE (When the bond was issued in the market) +// |MATURITY_DATE (End of life time of a product) +// |TRADABLE +// | +// |See [FPML](http://www.fpml.org/) for more examples. +// | +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// bankAttributeJsonV400, +// bankAttributeResponseJsonV400, +// List( +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute), +// Some(List(canCreateBankAttribute)) +// ) +// +// lazy val createBankAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "attribute" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 " +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[BankAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)" +// bankAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// BankAttributeType.withName(postedData.`type`) +// } +// (bankAttribute, callContext) <- NewStyle.function +// .createOrUpdateBankAttribute( +// BankId(bankId), +// None, +// postedData.name, +// bankAttributeType, +// postedData.value, +// postedData.is_active, +// callContext: Option[CallContext] +// ) +// } yield { +// (createBankAttributeJson(bankAttribute), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankAttributes, +// implementedInApiVersion, +// nameOf(getBankAttributes), +// "GET", +// "/banks/BANK_ID/attributes", +// "Get Bank Attributes", +// s""" Get Bank Attributes +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// bankAttributesResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute), +// Some(List(canGetBankAttribute)) +// ) +// +// lazy val getBankAttributes: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "attributes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributes, callContext) <- NewStyle.function +// .getBankAttributesByBank(bankId, cc.callContext) +// } yield { +// (createBankAttributesJson(attributes), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankAttribute, +// implementedInApiVersion, +// nameOf(getBankAttribute), +// "GET", +// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", +// "Get Bank Attribute By BANK_ATTRIBUTE_ID", +// s""" Get Bank Attribute By BANK_ATTRIBUTE_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// bankAttributeResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute), +// Some(List(canGetBankAttribute)) +// ) +// +// lazy val getBankAttribute: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attributes" :: bankAttributeId :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attribute, callContext) <- NewStyle.function.getBankAttributeById( +// bankAttributeId, +// cc.callContext +// ) +// } yield { +// (createBankAttributeJson(attribute), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankAttribute, +// implementedInApiVersion, +// nameOf(updateBankAttribute), +// "PUT", +// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", +// "Update Bank Attribute", +// s""" Update Bank Attribute. +// | +// |Update one Bak Attribute by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// bankAttributeJsonV400, +// bankAttributeDefinitionJsonV400, +// List( +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute) +// ) +// +// lazy val updateBankAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId, +// u.userId, +// canUpdateBankAttribute, +// callContext +// ) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $BankAttributeJsonV400 " +// postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[BankAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${BankAttributeType.DOUBLE}(12.1234), ${BankAttributeType.STRING}(TAX_NUMBER), ${BankAttributeType.INTEGER}(123) and ${BankAttributeType.DATE_WITH_DAY}(2012-04-23)" +// productAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// BankAttributeType.withName(postedData.`type`) +// } +// (_, callContext) <- NewStyle.function.getBankAttributeById( +// bankAttributeId, +// callContext +// ) +// (bankAttribute, callContext) <- NewStyle.function +// .createOrUpdateBankAttribute( +// BankId(bankId), +// Some(bankAttributeId), +// postedData.name, +// productAttributeType, +// postedData.value, +// postedData.is_active, +// callContext: Option[CallContext] +// ) +// } yield { +// ( +// createBankAttributeJson(bankAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankAttribute, +// implementedInApiVersion, +// nameOf(deleteBankAttribute), +// "DELETE", +// "/banks/BANK_ID/attributes/BANK_ATTRIBUTE_ID", +// "Delete Bank Attribute", +// s""" Delete Bank Attribute +// | +// |Delete a Bank Attribute by its id. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// UserHasMissingRoles, +// BankNotFound, +// UnknownError +// ), +// List(apiTagBank, apiTagBankAttribute, apiTagAttribute) +// ) +// +// lazy val deleteBankAttribute: OBPEndpoint = { +// case "banks" :: bankId :: "attributes" :: bankAttributeId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// _ <- NewStyle.function.hasEntitlement( +// bankId, +// u.userId, +// canDeleteBankAttribute, +// callContext +// ) +// (_, callContext) <- NewStyle.function.getBank( +// BankId(bankId), +// callContext +// ) +// (bankAttribute, callContext) <- NewStyle.function +// .deleteBankAttribute(bankAttributeId, callContext) +// } yield { +// (Full(bankAttribute), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateTransactionAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateTransactionAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/transaction", +// "Create or Update Transaction Attribute Definition", +// s""" Create or Update Transaction Attribute Definition +// | +// |The category field must be ${AttributeCategory.Transaction} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// transactionAttributeDefinitionJsonV400, +// transactionAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canCreateTransactionAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateTransactionAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "transaction" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Transaction}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createOrUpdateCardAttributeDefinition, +// implementedInApiVersion, +// nameOf(createOrUpdateCardAttributeDefinition), +// "PUT", +// "/banks/BANK_ID/attribute-definitions/card", +// "Create or Update Card Attribute Definition", +// s""" Create or Update Card Attribute Definition +// | +// |The category field must be ${AttributeCategory.Card} +// | +// |The type field must be one of; ${AttributeType.DOUBLE}, ${AttributeType.STRING}, ${AttributeType.INTEGER} and ${AttributeType.DATE_WITH_DAY} +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// cardAttributeDefinitionJsonV400, +// cardAttributeDefinitionResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagCard, apiTagCardAttribute, apiTagAttribute), +// Some(List(canCreateCardAttributeDefinitionAtOneBank)) +// ) +// +// lazy val createOrUpdateCardAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "card" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $AttributeDefinitionJsonV400 " +// for { +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// json.extract[AttributeDefinitionJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${AttributeType.DOUBLE}(12.1234), ${AttributeType.STRING}(TAX_NUMBER), ${AttributeType.INTEGER} (123)and ${AttributeType.DATE_WITH_DAY}(2012-04-23)" +// attributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// AttributeType.withName(postedData.`type`) +// } +// failMsg = +// s"$InvalidJsonFormat The `Category` field can only accept the following field: " + +// s"${AttributeCategory.Card}" +// category <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// AttributeCategory.withName(postedData.category) +// } +// (attributeDefinition, callContext) <- +// createOrUpdateAttributeDefinition( +// bankId, +// postedData.name, +// category, +// attributeType, +// postedData.description, +// postedData.alias, +// postedData.can_be_seen_on_views, +// postedData.is_active, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionJson(attributeDefinition), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteTransactionAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteTransactionAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/transaction", +// "Delete Transaction Attribute Definition", +// s""" Delete Transaction Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canDeleteTransactionAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteTransactionAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "transaction" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName( +// AttributeCategory.Transaction.toString +// ), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteCustomerAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteCustomerAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/customer", +// "Delete Customer Attribute Definition", +// s""" Delete Customer Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some(List(canDeleteCustomerAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteCustomerAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "customer" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName(AttributeCategory.Customer.toString), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteAccountAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteAccountAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/account", +// "Delete Account Attribute Definition", +// s""" Delete Account Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), +// Some(List(canDeleteAccountAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteAccountAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "account" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName(AttributeCategory.Account.toString), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteProductAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteProductAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/product", +// "Delete Product Attribute Definition", +// s""" Delete Product Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canDeleteProductAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteProductAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "product" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName(AttributeCategory.Product.toString), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteCardAttributeDefinition, +// implementedInApiVersion, +// nameOf(deleteCardAttributeDefinition), +// "DELETE", +// "/banks/BANK_ID/attribute-definitions/ATTRIBUTE_DEFINITION_ID/card", +// "Delete Card Attribute Definition", +// s""" Delete Card Attribute Definition by ATTRIBUTE_DEFINITION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCard, apiTagCardAttribute, apiTagAttribute), +// Some(List(canDeleteCardAttributeDefinitionAtOneBank)) +// ) +// +// lazy val deleteCardAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: attributeDefinitionId :: "card" :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- deleteAttributeDefinition( +// attributeDefinitionId, +// AttributeCategory.withName(AttributeCategory.Card.toString), +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProductAttributeDefinition, +// implementedInApiVersion, +// nameOf(getProductAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/product", +// "Get Product Attribute Definition", +// s""" Get Product Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// productAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagProduct, apiTagProductAttribute, apiTagAttribute), +// Some(List(canGetProductAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getProductAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "product" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName(AttributeCategory.Product.toString), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomerAttributeDefinition, +// implementedInApiVersion, +// nameOf(getCustomerAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/customer", +// "Get Customer Attribute Definition", +// s""" Get Customer Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customerAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer, apiTagCustomerAttribute, apiTagAttribute), +// Some(List(canGetCustomerAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getCustomerAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "customer" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName(AttributeCategory.Customer.toString), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAccountAttributeDefinition, +// implementedInApiVersion, +// nameOf(getAccountAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/account", +// "Get Account Attribute Definition", +// s""" Get Account Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// accountAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagAccount, apiTagAccountAttribute, apiTagAttribute), +// Some(List(canGetAccountAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getAccountAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "account" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName(AttributeCategory.Account.toString), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getTransactionAttributeDefinition, +// implementedInApiVersion, +// nameOf(getTransactionAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/transaction", +// "Get Transaction Attribute Definition", +// s""" Get Transaction Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// transactionAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagTransaction, apiTagTransactionAttribute, apiTagAttribute), +// Some(List(canGetTransactionAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getTransactionAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "transaction" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName( +// AttributeCategory.Transaction.toString +// ), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson( +// attributeDefinitions +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCardAttributeDefinition, +// implementedInApiVersion, +// nameOf(getCardAttributeDefinition), +// "GET", +// "/banks/BANK_ID/attribute-definitions/card", +// "Get Card Attribute Definition", +// s""" Get Card Attribute Definition +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// cardAttributeDefinitionsResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCard, apiTagCardAttribute, apiTagAttribute), +// Some(List(canGetCardAttributeDefinitionAtOneBank)) +// ) +// +// lazy val getCardAttributeDefinition: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "attribute-definitions" :: "card" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributeDefinitions, callContext) <- getAttributeDefinition( +// AttributeCategory.withName(AttributeCategory.Card.toString), +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createAttributeDefinitionsJson(attributeDefinitions), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteUserCustomerLink, +// implementedInApiVersion, +// nameOf(deleteUserCustomerLink), +// "DELETE", +// "/banks/BANK_ID/user_customer_links/USER_CUSTOMER_LINK_ID", +// "Delete User Customer Link", +// s""" Delete User Customer Link by USER_CUSTOMER_LINK_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canDeleteUserCustomerLink)) +// ) +// +// lazy val deleteUserCustomerLink: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user_customer_links" :: userCustomerLinkId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (deleted, callContext) <- UserCustomerLinkNewStyle +// .deleteUserCustomerLink( +// userCustomerLinkId, +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserCustomerLinksByUserId, +// implementedInApiVersion, +// nameOf(getUserCustomerLinksByUserId), +// "GET", +// "/banks/BANK_ID/user_customer_links/users/USER_ID", +// "Get User Customer Links by User", +// s""" Get User Customer Links by USER_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// userCustomerLinksJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canGetUserCustomerLink)) +// ) +// +// lazy val getUserCustomerLinksByUserId: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user_customer_links" :: "users" :: userId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle +// .getUserCustomerLinksByUserId( +// userId, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createUserCustomerLinks, +// implementedInApiVersion, +// "createUserCustomerLinks", +// "POST", +// "/banks/BANK_ID/user_customer_links", +// "Create User Customer Link", +// s"""Link a User to a Customer +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// createUserCustomerLinkJson, +// userCustomerLinkJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidBankIdFormat, +// $BankNotFound, +// InvalidJsonFormat, +// CustomerNotFoundByCustomerId, +// UserHasMissingRoles, +// CustomerAlreadyExistsForUser, +// CreateUserCustomerLinksError, +// UnknownError +// ), +// List(apiTagCustomer, apiTagUser), +// Some(List(canCreateUserCustomerLinkAtAnyBank, canCreateUserCustomerLink)) +// ) +// +// lazy val createUserCustomerLinks: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user_customer_links" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- NewStyle.function.tryons( +// s"$InvalidBankIdFormat", +// 400, +// cc.callContext +// ) { +// assert(isValidID(bankId.value)) +// } +// postedData <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $CreateUserCustomerLinkJson ", +// 400, +// cc.callContext +// ) { +// json.extract[CreateUserCustomerLinkJson] +// } +// user <- Users.users.vend.getUserByUserIdFuture( +// postedData.user_id +// ) map { x => +// unboxFullOrFail(x, cc.callContext, UserNotFoundByUserId, 404) +// } +// _ <- booleanToFuture( +// "Field customer_id is not defined in the posted json!", +// 400, +// cc.callContext +// ) { +// postedData.customer_id.nonEmpty +// } +// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId( +// postedData.customer_id, +// cc.callContext +// ) +// _ <- booleanToFuture( +// s"Bank of the customer specified by the CUSTOMER_ID(${customer.bankId}) has to matches BANK_ID(${bankId.value}) in URL", +// 400, +// callContext +// ) { +// customer.bankId == bankId.value +// } +// _ <- booleanToFuture(CustomerAlreadyExistsForUser, 400, callContext) { +// UserCustomerLink.userCustomerLink.vend +// .getUserCustomerLink(postedData.user_id, postedData.customer_id) +// .isEmpty == true +// } +// userCustomerLink <- Future { +// UserCustomerLink.userCustomerLink.vend.createUserCustomerLink( +// postedData.user_id, +// postedData.customer_id, +// new Date(), +// true +// ) +// } map { x => +// unboxFullOrFail(x, callContext, CreateUserCustomerLinksError, 400) +// } +// } yield { +// ( +// code.api.v2_0_0.JSONFactory200 +// .createUserCustomerLinkJSON(userCustomerLink), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserCustomerLinksByCustomerId, +// implementedInApiVersion, +// nameOf(getUserCustomerLinksByCustomerId), +// "GET", +// "/banks/BANK_ID/user_customer_links/customers/CUSTOMER_ID", +// "Get User Customer Links by Customer", +// s""" Get User Customer Links by CUSTOMER_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// userCustomerLinksJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canGetUserCustomerLink)) +// ) +// +// lazy val getUserCustomerLinksByCustomerId: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "user_customer_links" :: "customers" :: customerId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (userCustomerLinks, callContext) <- getUserCustomerLinks( +// customerId, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory200.createUserCustomerLinkJSONs(userCustomerLinks), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCorrelatedUsersInfoByCustomerId, +// implementedInApiVersion, +// nameOf(getCorrelatedUsersInfoByCustomerId), +// "GET", +// "/banks/BANK_ID/customers/CUSTOMER_ID/correlated-users", +// "Get Correlated User Info by Customer", +// s"""Get Correlated User Info by CUSTOMER_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// customerAndUsersWithAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canGetCorrelatedUsersInfoAtAnyBank, canGetCorrelatedUsersInfo)) +// ) +// +// lazy val getCorrelatedUsersInfoByCustomerId: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "customers" :: customerId :: "correlated-users" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, cc.callContext) +// (userCustomerLinks, callContext) <- getUserCustomerLinks( +// customerId, +// callContext +// ) +// (users, callContext) <- NewStyle.function.getUsersByUserIds( +// userCustomerLinks.map(_.userId), +// callContext +// ) +// (attributes, callContext) <- NewStyle.function +// .getUserAttributesByUsers( +// userCustomerLinks.map(_.userId), +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerAdUsersWithAttributesJson( +// customer, +// users, +// attributes +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyCorrelatedEntities, +// implementedInApiVersion, +// nameOf(getMyCorrelatedEntities), +// "GET", +// "/my/correlated-entities", +// "Get Correlated Entities for the current User", +// s"""Correlated Entities are users and customers linked to the currently authenticated user via User-Customer-Links +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// correlatedUsersResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagCustomer) +// ) +// +// private def getCorrelatedUsersInfo( +// userCustomerLink: UserCustomerLink, +// callContext: Option[CallContext] +// ) = for { +// (customer, callContext) <- NewStyle.function.getCustomerByCustomerId( +// userCustomerLink.customerId, +// callContext +// ) +// (userCustomerLinks, callContext) <- getUserCustomerLinks( +// userCustomerLink.customerId, +// callContext +// ) +// (users, callContext) <- NewStyle.function.getUsersByUserIds( +// userCustomerLinks.map(_.userId), +// callContext +// ) +// (attributes, callContext) <- NewStyle.function.getUserAttributesByUsers( +// userCustomerLinks.map(_.userId), +// callContext +// ) +// } yield { +// (customer, users, attributes, callContext) +// } +// +// lazy val getMyCorrelatedEntities: OBPEndpoint = { +// case "my" :: "correlated-entities" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// (userCustomerLinks, callContext) <- UserCustomerLinkNewStyle +// .getUserCustomerLinksByUserId( +// u.userId, +// callContext +// ) +// correlatedUserInfoList <- Future.sequence( +// userCustomerLinks.map(getCorrelatedUsersInfo(_, callContext)) +// ) +// } yield { +// ( +// CorrelatedEntities( +// correlatedUserInfoList.map(correlatedUserInfo => +// JSONFactory400.createCustomerAdUsersWithAttributesJson( +// correlatedUserInfo._1, +// correlatedUserInfo._2, +// correlatedUserInfo._3 +// ) +// ) +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createCustomer, +// implementedInApiVersion, +// nameOf(createCustomer), +// "POST", +// "/banks/BANK_ID/customers", +// "Create Customer", +// s""" +// |The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc. +// |Dates need to be in the format 2013-01-21T23:08:00Z +// | +// |Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call. +// | +// |${userAuthenticationMessage(true)} +// |""", +// postCustomerJsonV310, +// customerJsonV310, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// CustomerNumberAlreadyExists, +// UserNotFoundById, +// CustomerAlreadyExistsForUser, +// CreateConsumerError, +// UnknownError +// ), +// List(apiTagCustomer, apiTagPerson), +// Some(List(canCreateCustomer, canCreateCustomerAtAnyBank)) +// ) +// lazy val createCustomer: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "customers" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postedData <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 ", +// 400, +// cc.callContext +// ) { +// json.extract[PostCustomerJsonV310] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// InvalidJsonContent + s" The field dependants(${postedData.dependants}) not equal the length(${postedData.dob_of_dependants.length}) of dob_of_dependants array", +// 400, +// cc.callContext +// ) { +// postedData.dependants == postedData.dob_of_dependants.length +// } +// (customer, callContext) <- NewStyle.function.createCustomer( +// bankId, +// postedData.legal_name, +// postedData.mobile_phone_number, +// postedData.email, +// CustomerFaceImage( +// postedData.face_image.date, +// postedData.face_image.url +// ), +// postedData.date_of_birth, +// postedData.relationship_status, +// postedData.dependants, +// postedData.dob_of_dependants, +// postedData.highest_education_attained, +// postedData.employment_status, +// postedData.kyc_status, +// postedData.last_ok_date, +// Option( +// CreditRating( +// postedData.credit_rating.rating, +// postedData.credit_rating.source +// ) +// ), +// Option( +// CreditLimit( +// postedData.credit_limit.currency, +// postedData.credit_limit.amount +// ) +// ), +// postedData.title, +// postedData.branch_id, +// postedData.name_suffix, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory310.createCustomerJson(customer), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAccountsMinimalByCustomerId, +// implementedInApiVersion, +// nameOf(getAccountsMinimalByCustomerId), +// "GET", +// "/customers/CUSTOMER_ID/accounts-minimal", +// "Get Accounts Minimal for a Customer", +// s"""Get Accounts Minimal by CUSTOMER_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// accountsMinimalJson400, +// List( +// $AuthenticatedUserIsRequired, +// CustomerNotFound, +// UnknownError +// ), +// List(apiTagAccount), +// Some(List(canGetAccountsMinimalForCustomerAtOneBank, canGetAccountsMinimalForCustomerAtAnyBank)) +// ) +// +// lazy val getAccountsMinimalByCustomerId: OBPEndpoint = { +// case "customers" :: customerId :: "accounts-minimal" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// (customer, callContext) <- getCustomerByCustomerId( +// customerId, +// callContext +// ) +// _ <- NewStyle.function.hasAtLeastOneEntitlement(customer.bankId, u.userId, canGetAccountsMinimalForCustomerAtOneBank :: canGetAccountsMinimalForCustomerAtAnyBank :: Nil, callContext) +// (userCustomerLinks, callContext) <- getUserCustomerLinks( +// customerId, +// callContext +// ) +// (users, callContext) <- getUsersByUserIds( +// userCustomerLinks.map(_.userId), +// callContext +// ) +// } yield { +// val accountAccess = +// for (user <- users) +// yield Views.views.vend.privateViewsUserCanAccess(user)._2 +// ( +// JSONFactory400.createAccountsMinimalJson400( +// accountAccess.flatten +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteTransactionCascade, +// implementedInApiVersion, +// nameOf(deleteTransactionCascade), +// "DELETE", +// "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID", +// "Delete Transaction Cascade", +// s"""Delete a Transaction Cascade specified by TRANSACTION_ID. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagTransaction), +// Some(List(canDeleteTransactionCascade)) +// ) +// +// lazy val deleteTransactionCascade: OBPEndpoint = { +// case "management" :: "cascading" :: "banks" :: BankId( +// bankId +// ) :: "accounts" :: AccountId(accountId) :: +// "transactions" :: TransactionId( +// transactionId +// ) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getTransaction( +// bankId, +// accountId, +// transactionId, +// cc.callContext +// ) +// _ <- Future( +// DeleteTransactionCascade.atomicDelete( +// bankId, +// accountId, +// transactionId +// ) +// ) +// } yield { +// (Full(true), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteAccountCascade, +// implementedInApiVersion, +// nameOf(deleteAccountCascade), +// "DELETE", +// "/management/cascading/banks/BANK_ID/accounts/ACCOUNT_ID", +// "Delete Account Cascade", +// s"""Delete an Account Cascade specified by ACCOUNT_ID. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagAccount), +// Some(List(canDeleteAccountCascade)) +// ) +// +// lazy val deleteAccountCascade: OBPEndpoint = { +// case "management" :: "cascading" :: "banks" :: BankId( +// bankId +// ) :: "accounts" :: AccountId(accountId) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// result <- Future(DeleteAccountCascade.atomicDelete(bankId, accountId)) +// } yield { +// if (result.getOrElse(false)) +// (Full(true), HttpCode.`200`(cc)) +// else +// (Full(false), HttpCode.`404`(cc)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankCascade, +// implementedInApiVersion, +// nameOf(deleteBankCascade), +// "DELETE", +// "/management/cascading/banks/BANK_ID", +// "Delete Bank Cascade", +// s"""Delete a Bank Cascade specified by BANK_ID. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagBank), +// Some(List(canDeleteBankCascade)) +// ) +// +// lazy val deleteBankCascade: OBPEndpoint = { +// case "management" :: "cascading" :: "banks" :: BankId( +// bankId +// ) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// _ <- Future(DeleteBankCascade.atomicDelete(bankId)) +// } yield { +// (Full(true), HttpCode.`200`(cc)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteProductCascade, +// implementedInApiVersion, +// nameOf(deleteProductCascade), +// "DELETE", +// "/management/cascading/banks/BANK_ID/products/PRODUCT_CODE", +// "Delete Product Cascade", +// s"""Delete a Product Cascade specified by PRODUCT_CODE. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct), +// Some(List(canDeleteProductCascade)) +// ) +// +// lazy val deleteProductCascade: OBPEndpoint = { +// case "management" :: "cascading" :: "banks" :: BankId( +// bankId +// ) :: "products" :: ProductCode(code) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getProduct( +// bankId, +// code, +// Some(cc) +// ) +// _ <- Future(DeleteProductCascade.atomicDelete(bankId, code)) +// } yield { +// (Full(true), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteCustomerCascade, +// implementedInApiVersion, +// nameOf(deleteCustomerCascade), +// "DELETE", +// "/management/cascading/banks/BANK_ID/customers/CUSTOMER_ID", +// "Delete Customer Cascade", +// s"""Delete a Customer Cascade specified by CUSTOMER_ID. +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// CustomerNotFoundByCustomerId, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagCustomer), +// Some(List(canDeleteCustomerCascade)) +// ) +// +// lazy val deleteCustomerCascade: OBPEndpoint = { +// case "management" :: "cascading" :: "banks" :: BankId( +// bankId +// ) :: "customers" :: CustomerId(customerId) :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getCustomerByCustomerId( +// customerId.value, +// Some(cc) +// ) +// _ <- Future(DeleteCustomerCascade.atomicDelete(customerId)) +// } yield { +// (Full(true), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createExplicitCounterparty, +// implementedInApiVersion, +// "createCounterparty", +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", +// "Create Counterparty (Explicit)", +// s"""This endpoint creates an (Explicit) Counterparty for an Account. +// | +// |For an introduction to Counterparties in OBP see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// postCounterpartyJson400, +// counterpartyWithMetadataJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// InvalidJsonFormat, +// InvalidISOCurrencyCode, +// ViewNotFound, +// CounterpartyAlreadyExists, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount) +// ) +// +// lazy val createExplicitCounterparty: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// InvalidAccountIdFormat, +// cc = callContext +// ) { isValidID(accountId.value) } +// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { +// isValidID(bankId.value) +// } +// postJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostCounterpartyJSON", +// 400, +// callContext +// ) { +// json.extract[PostCounterpartyJson400] +// } +// +// _ <- Helper.booleanToFuture( +// s"$NoViewPermission can_add_counterparty. Please use a view with that permission or add the permission to this view.", +// 403, +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_ADD_COUNTERPARTY) +// } +// +// (counterparty, callContext) <- Connector.connector.vend +// .checkCounterpartyExists( +// postJson.name, +// bankId.value, +// accountId.value, +// viewId.value, +// callContext +// ) +// +// _ <- Helper.booleanToFuture( +// CounterpartyAlreadyExists.replace( +// "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.", +// s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" +// ), +// cc = callContext +// ) { +// counterparty.isEmpty +// } +// _ <- booleanToFuture( +// s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}", +// cc = callContext +// ) { +// postJson.description.length <= 36 +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'", +// cc = callContext +// ) { +// APIUtil.isValidCurrencyISOCode(postJson.currency) +// } +// +// // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account. +// (_, callContext) <- +// if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) && postJson.other_account_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) +// ) { +// for { +// (_, callContext) <- NewStyle.function.getBank( +// BankId(postJson.other_bank_routing_address), +// Some(cc) +// ) +// (account, callContext) <- NewStyle.function +// .checkBankAccountExists( +// BankId(postJson.other_bank_routing_address), +// AccountId(postJson.other_account_routing_address), +// callContext +// ) +// +// } yield { +// (account, callContext) +// } +// } else if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) && postJson.other_account_secondary_routing_scheme +// .equalsIgnoreCase("OBP") +// ) { +// for { +// (_, callContext) <- NewStyle.function.getBank( +// BankId(postJson.other_bank_routing_address), +// Some(cc) +// ) +// (account, callContext) <- NewStyle.function +// .checkBankAccountExists( +// BankId(postJson.other_bank_routing_address), +// AccountId( +// postJson.other_account_secondary_routing_address +// ), +// callContext +// ) +// +// } yield { +// (account, callContext) +// } +// } else if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "ACCOUNT_NUMBER" +// ) || postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "ACCOUNT_NO" +// ) +// ) { +// for { +// bankIdOption <- Future.successful( +// if (postJson.other_bank_routing_address.isEmpty) None +// else Some(postJson.other_bank_routing_address) +// ) +// (account, callContext) <- NewStyle.function +// .getBankAccountByNumber( +// bankIdOption.map(BankId(_)), +// postJson.other_bank_routing_address, +// callContext +// ) +// } yield { +// (account, callContext) +// } +// } else +// Future { (Full(()), Some(cc)) } +// +// otherAccountRoutingSchemeOBPFormat = +// if ( +// postJson.other_account_routing_scheme.equalsIgnoreCase( +// "AccountNo" +// ) +// ) "ACCOUNT_NUMBER" +// else +// StringHelpers +// .snakify(postJson.other_account_routing_scheme) +// .toUpperCase +// +// (counterparty, callContext) <- NewStyle.function.createCounterparty( +// name = postJson.name, +// description = postJson.description, +// currency = postJson.currency, +// createdByUserId = u.userId, +// thisBankId = bankId.value, +// thisAccountId = accountId.value, +// thisViewId = viewId.value, +// otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat, +// otherAccountRoutingAddress = +// postJson.other_account_routing_address, +// otherAccountSecondaryRoutingScheme = StringHelpers +// .snakify(postJson.other_account_secondary_routing_scheme) +// .toUpperCase, +// otherAccountSecondaryRoutingAddress = +// postJson.other_account_secondary_routing_address, +// otherBankRoutingScheme = StringHelpers +// .snakify(postJson.other_bank_routing_scheme) +// .toUpperCase, +// otherBankRoutingAddress = postJson.other_bank_routing_address, +// otherBranchRoutingScheme = StringHelpers +// .snakify(postJson.other_branch_routing_scheme) +// .toUpperCase, +// otherBranchRoutingAddress = postJson.other_branch_routing_address, +// isBeneficiary = postJson.is_beneficiary, +// bespoke = postJson.bespoke.map(bespoke => +// CounterpartyBespoke(bespoke.key, bespoke.value) +// ), +// callContext +// ) +// +// (counterpartyMetadata, callContext) <- NewStyle.function +// .getOrCreateMetadata( +// bankId, +// accountId, +// counterparty.counterpartyId, +// postJson.name, +// callContext +// ) +// +// } yield { +// ( +// JSONFactory400.createCounterpartyWithMetadataJson400( +// counterparty, +// counterpartyMetadata +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteExplicitCounterparty, +// implementedInApiVersion, +// nameOf(deleteExplicitCounterparty), +// "POST", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", +// "Delete Counterparty (Explicit)", +// s"""This endpoint deletes the Counterparty on the Account / View specified by the COUNTERPARTY_ID. +// |It also deletes any related Counterparty Metadata. +// | +// |The User calling this endpoint must have access to the View specified in the URL and that View must have the permission `can_delete_counterparty`. +// | +// |For a general introduction to Counterparties in OBP see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount) +// ) +// +// lazy val deleteExplicitCounterparty: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( +// counterpartyId +// ) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// InvalidAccountIdFormat, +// cc = callContext +// ) { isValidID(accountId.value) } +// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { +// isValidID(bankId.value) +// } +// +// _ <- Helper.booleanToFuture( +// s"$NoViewPermission can_delete_counterparty. Please use a view with that permission or add the permission to this view.", +// 403, +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_DELETE_COUNTERPARTY) +// } +// +// (counterparty, callContext) <- NewStyle.function +// .deleteCounterpartyByCounterpartyId(counterpartyId, callContext) +// +// (counterpartyMetadata, callContext) <- NewStyle.function +// .deleteMetadata( +// bankId, +// accountId, +// counterpartyId.value, +// callContext +// ) +// +// } yield { +// (Full(counterparty), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteCounterpartyForAnyAccount, +// implementedInApiVersion, +// nameOf(deleteCounterpartyForAnyAccount), +// "DELETE", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", +// "Delete Counterparty for any account (Explicit)", +// s"""This is a management endpoint that enables the deletion of any specified Counterparty along with any related Metadata of that Counterparty. +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// $BankAccountNotFound, +// $BankNotFound, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount), +// Some(List(canDeleteCounterparty, canDeleteCounterpartyAtAnyBank)) +// ) +// +// lazy val deleteCounterpartyForAnyAccount: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( +// counterpartyId +// ) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount +// +// _ <- Helper.booleanToFuture( +// InvalidAccountIdFormat, +// cc = callContext +// ) { isValidID(accountId.value) } +// +// _ <- Helper.booleanToFuture(InvalidBankIdFormat, cc = callContext) { +// isValidID(bankId.value) +// } +// +// (counterparty, callContext) <- NewStyle.function +// .deleteCounterpartyByCounterpartyId(counterpartyId, callContext) +// +// (counterpartyMetadata, callContext) <- NewStyle.function +// .deleteMetadata( +// bankId, +// accountId, +// counterpartyId.value, +// callContext +// ) +// +// } yield { +// (Full(counterparty), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createCounterpartyForAnyAccount, +// implementedInApiVersion, +// "createCounterpartyForAnyAccount", +// "POST", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", +// "Create Counterparty for any account (Explicit)", +// s"""This is a management endpoint that allows the creation of a Counterparty on any Account. +// | +// |For an introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// postCounterpartyJson400, +// counterpartyWithMetadataJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// $BankNotFound, +// $BankAccountNotFound, +// AccountNotFound, +// InvalidJsonFormat, +// InvalidISOCurrencyCode, +// ViewNotFound, +// CounterpartyAlreadyExists, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount), +// Some(List(canCreateCounterparty, canCreateCounterpartyAtAnyBank)) +// ) +// +// lazy val createCounterpartyForAnyAccount: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount +// postJson <- NewStyle.function.tryons( +// InvalidJsonFormat, +// 400, +// callContext +// ) { +// json.extract[PostCounterpartyJson400] +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidValueLength. The maximum length of `description` field is ${MappedCounterparty.mDescription.maxLen}", +// cc = callContext +// ) { postJson.description.length <= 36 } +// +// (counterparty, callContext) <- Connector.connector.vend +// .checkCounterpartyExists( +// postJson.name, +// bankId.value, +// accountId.value, +// viewId.value, +// callContext +// ) +// +// _ <- Helper.booleanToFuture( +// CounterpartyAlreadyExists.replace( +// "value for BANK_ID or ACCOUNT_ID or VIEW_ID or NAME.", +// s"COUNTERPARTY_NAME(${postJson.name}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" +// ), +// cc = callContext +// ) { +// counterparty.isEmpty +// } +// +// _ <- Helper.booleanToFuture( +// s"$InvalidISOCurrencyCode Current input is: '${postJson.currency}'", +// cc = callContext +// ) { +// APIUtil.isValidCurrencyISOCode(postJson.currency) +// } +// +// // If other_account_routing_scheme=="OBP" or other_account_secondary_routing_address=="OBP" we will check if it is a real obp bank account. +// (_, callContext) <- +// if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) && postJson.other_account_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) +// ) { +// for { +// (_, callContext) <- NewStyle.function.getBank( +// BankId(postJson.other_bank_routing_address), +// Some(cc) +// ) +// (account, callContext) <- NewStyle.function +// .checkBankAccountExists( +// BankId(postJson.other_bank_routing_address), +// AccountId(postJson.other_account_routing_address), +// callContext +// ) +// +// } yield { +// (account, callContext) +// } +// } else if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "OBP" +// ) && postJson.other_account_secondary_routing_scheme +// .equalsIgnoreCase("OBP") +// ) { +// for { +// (_, callContext) <- NewStyle.function.getBank( +// BankId(postJson.other_bank_routing_address), +// Some(cc) +// ) +// (account, callContext) <- NewStyle.function +// .checkBankAccountExists( +// BankId(postJson.other_bank_routing_address), +// AccountId( +// postJson.other_account_secondary_routing_address +// ), +// callContext +// ) +// +// } yield { +// (account, callContext) +// } +// } else if ( +// postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "ACCOUNT_NUMBER" +// ) || postJson.other_bank_routing_scheme.equalsIgnoreCase( +// "ACCOUNT_NO" +// ) +// ) { +// for { +// bankIdOption <- Future.successful( +// if (postJson.other_bank_routing_address.isEmpty) None +// else Some(postJson.other_bank_routing_address) +// ) +// (account, callContext) <- NewStyle.function +// .getBankAccountByNumber( +// bankIdOption.map(BankId(_)), +// postJson.other_bank_routing_address, +// callContext +// ) +// } yield { +// (account, callContext) +// } +// } else +// Future { (Full(()), Some(cc)) } +// +// otherAccountRoutingSchemeOBPFormat = +// if ( +// postJson.other_account_routing_scheme.equalsIgnoreCase( +// "AccountNo" +// ) +// ) "ACCOUNT_NUMBER" +// else +// StringHelpers +// .snakify(postJson.other_account_routing_scheme) +// .toUpperCase +// +// (counterparty, callContext) <- NewStyle.function.createCounterparty( +// name = postJson.name, +// description = postJson.description, +// currency = postJson.currency, +// createdByUserId = u.userId, +// thisBankId = bankId.value, +// thisAccountId = accountId.value, +// thisViewId = Constant.SYSTEM_OWNER_VIEW_ID, +// otherAccountRoutingScheme = otherAccountRoutingSchemeOBPFormat, +// otherAccountRoutingAddress = +// postJson.other_account_routing_address, +// otherAccountSecondaryRoutingScheme = StringHelpers +// .snakify(postJson.other_account_secondary_routing_scheme) +// .toUpperCase, +// otherAccountSecondaryRoutingAddress = +// postJson.other_account_secondary_routing_address, +// otherBankRoutingScheme = StringHelpers +// .snakify(postJson.other_bank_routing_scheme) +// .toUpperCase, +// otherBankRoutingAddress = postJson.other_bank_routing_address, +// otherBranchRoutingScheme = StringHelpers +// .snakify(postJson.other_branch_routing_scheme) +// .toUpperCase, +// otherBranchRoutingAddress = postJson.other_branch_routing_address, +// isBeneficiary = postJson.is_beneficiary, +// bespoke = postJson.bespoke.map(bespoke => +// CounterpartyBespoke(bespoke.key, bespoke.value) +// ), +// callContext +// ) +// +// (counterpartyMetadata, callContext) <- NewStyle.function +// .getOrCreateMetadata( +// bankId, +// accountId, +// counterparty.counterpartyId, +// postJson.name, +// callContext +// ) +// +// } yield { +// ( +// JSONFactory400.createCounterpartyWithMetadataJson400( +// counterparty, +// counterpartyMetadata +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getExplicitCounterpartiesForAccount, +// implementedInApiVersion, +// "getExplicitCounterpartiesForAccount", +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", +// "Get Counterparties (Explicit)", +// s"""Get the Counterparties that have been explicitly created on the specified Account / View. +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// counterpartiesJson400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// ViewNotFound, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount) +// ) +// +// lazy val getExplicitCounterpartiesForAccount: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = s"${NoViewPermission}can_get_counterparty", +// 403, +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY) +// } +// (counterparties, callContext) <- NewStyle.function.getCounterparties( +// bankId, +// accountId, +// viewId, +// callContext +// ) +// // Here we need create the metadata for all the explicit counterparties. maybe show them in json response. +// // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata. +// _ <- Helper.booleanToFuture( +// CreateOrUpdateCounterpartyMetadataError, +// 400, +// cc = callContext +// ) { +// { +// for { +// counterparty <- counterparties +// } yield { +// Counterparties.counterparties.vend.getOrCreateMetadata( +// bankId, +// accountId, +// counterparty.counterpartyId, +// counterparty.name +// ) match { +// case Full(_) => true +// case _ => false +// } +// } +// }.forall(_ == true) +// } +// } yield { +// val counterpartiesJson = +// JSONFactory400.createCounterpartiesJson400(counterparties) +// (counterpartiesJson, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCounterpartiesForAnyAccount, +// implementedInApiVersion, +// nameOf(getCounterpartiesForAnyAccount), +// "GET", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties", +// "Get Counterparties for any account (Explicit)", +// s"""This is a management endpoint that gets the Counterparties that have been explicitly created for an Account / View. +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// counterpartiesJson400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagPSD2PIS, apiTagPsd2, apiTagAccount), +// Some(List(canGetCounterparties, canGetCounterpartiesAtAnyBank)) +// ) +// +// lazy val getCounterpartiesForAnyAccount: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount +// (counterparties, callContext) <- NewStyle.function.getCounterparties( +// bankId, +// accountId, +// viewId, +// callContext +// ) +// // Here we need create the metadata for all the explicit counterparties. maybe show them in json response. +// // Note: actually we need update all the counterparty metadata when they from adapter. Some counterparties may be the first time to api, there is no metadata. +// _ <- Helper.booleanToFuture( +// CreateOrUpdateCounterpartyMetadataError, +// 400, +// cc = callContext +// ) { +// { +// for { +// counterparty <- counterparties +// } yield { +// Counterparties.counterparties.vend.getOrCreateMetadata( +// bankId, +// accountId, +// counterparty.counterpartyId, +// counterparty.name +// ) match { +// case Full(_) => true +// case _ => false +// } +// } +// }.forall(_ == true) +// } +// } yield { +// val counterpartiesJson = +// JSONFactory400.createCounterpartiesJson400(counterparties) +// (counterpartiesJson, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getExplicitCounterpartyById, +// implementedInApiVersion, +// "getExplicitCounterpartyById", +// "GET", +// "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", +// "Get Counterparty by Id (Explicit)", +// s"""This endpoint returns a single Counterparty on an Account View specified by its COUNTERPARTY_ID: +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// counterpartyWithMetadataJson400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// $BankAccountNotFound, +// $UserNoPermissionAccessView, +// UnknownError +// ), +// List( +// apiTagCounterparty, +// apiTagPSD2PIS, +// apiTagPsd2, +// apiTagCounterpartyMetaData +// ) +// ) +// +// lazy val getExplicitCounterpartyById: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( +// counterpartyId +// ) :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, view, callContext) <- +// SS.userBankAccountView +// _ <- Helper.booleanToFuture( +// failMsg = s"${NoViewPermission}can_get_counterparty", +// 403, +// cc = callContext +// ) { +// view.allowed_actions.exists(_ == CAN_GET_COUNTERPARTY) +// } +// (counterparty, callContext) <- NewStyle.function +// .getCounterpartyByCounterpartyId(counterpartyId, callContext) +// counterpartyMetadata <- NewStyle.function.getMetadata( +// bankId, +// accountId, +// counterpartyId.value, +// callContext +// ) +// } yield { +// val counterpartyJson = +// JSONFactory400.createCounterpartyWithMetadataJson400( +// counterparty, +// counterpartyMetadata +// ) +// (counterpartyJson, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCounterpartyByNameForAnyAccount, +// implementedInApiVersion, +// nameOf(getCounterpartyByNameForAnyAccount), +// "GET", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparty-names/COUNTERPARTY_NAME", +// "Get Counterparty by name for any account (Explicit) ", +// s"""This is a management endpoint that allows the retrieval of any Counterparty on an Account / View by its Name. +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// EmptyBody, +// counterpartyWithMetadataJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// ViewNotFound, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount), +// Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty)) +// ) +// +// lazy val getCounterpartyByNameForAnyAccount: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId( +// viewId +// ) :: "counterparty-names" :: counterpartyName :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), bank, account, callContext) <- SS.userBankAccount +// +// (counterparty, callContext) <- Connector.connector.vend +// .checkCounterpartyExists( +// counterpartyName, +// bankId.value, +// accountId.value, +// viewId.value, +// callContext +// ) +// +// counterparty <- NewStyle.function.tryons( +// CounterpartyNotFound.replace( +// "The BANK_ID / ACCOUNT_ID specified does not exist on this server.", +// s"COUNTERPARTY_NAME(${counterpartyName}) for the BANK_ID(${bankId.value}) and ACCOUNT_ID(${accountId.value}) and VIEW_ID($viewId)" +// ), +// 400, +// callContext +// ) { +// counterparty.head +// } +// +// (counterpartyMetadata, callContext) <- NewStyle.function +// .getOrCreateMetadata( +// bankId, +// accountId, +// counterparty.counterpartyId, +// counterparty.name, +// callContext +// ) +// +// } yield { +// ( +// JSONFactory400.createCounterpartyWithMetadataJson400( +// counterparty, +// counterpartyMetadata +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCounterpartyByIdForAnyAccount, +// implementedInApiVersion, +// nameOf(getCounterpartyByIdForAnyAccount), +// "GET", +// "/management/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", +// "Get Counterparty by Id for any account (Explicit)", +// s"""This is a management endpoint that gets information about any single explicitly created Counterparty on an Account / View specified by its COUNTERPARTY_ID", +// | +// |For a general introduction to Counterparties in OBP, see ${Glossary +// .getGlossaryItemLink("Counterparties")} +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// EmptyBody, +// counterpartyWithMetadataJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidAccountIdFormat, +// InvalidBankIdFormat, +// $BankNotFound, +// $BankAccountNotFound, +// InvalidJsonFormat, +// ViewNotFound, +// UnknownError +// ), +// List(apiTagCounterparty, apiTagAccount), +// Some(List(canGetCounterpartyAtAnyBank, canGetCounterparty)) +// ) +// +// lazy val getCounterpartyByIdForAnyAccount: OBPEndpoint = { +// case "management" :: "banks" :: BankId(bankId) :: "accounts" :: AccountId( +// accountId +// ) :: ViewId(viewId) :: "counterparties" :: CounterpartyId( +// counterpartyId +// ) :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user @ Full(u), _, account, callContext) <- SS.userBankAccount +// (counterparty, callContext) <- NewStyle.function +// .getCounterpartyByCounterpartyId(counterpartyId, callContext) +// counterpartyMetadata <- NewStyle.function.getMetadata( +// bankId, +// accountId, +// counterpartyId.value, +// callContext +// ) +// } yield { +// val counterpartyJson = +// JSONFactory400.createCounterpartyWithMetadataJson400( +// counterparty, +// counterpartyMetadata +// ) +// (counterpartyJson, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// addConsentUser, +// implementedInApiVersion, +// nameOf(addConsentUser), +// "PUT", +// "/banks/BANK_ID/consents/CONSENT_ID/user-update-request", +// "Add User to a Consent", +// s""" +// | +// | +// |This endpoint is used to add the User of Consent. +// | +// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted +// .mkString(", ")}. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// PutConsentUserJsonV400(user_id = "ed7a7c01-db37-45cc-ba12-0ae8891c195c"), +// ConsentChallengeJsonV310( +// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945", +// jwt = +// "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4", +// status = "AUTHORISED" +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// $BankNotFound, +// ConsentUserAlreadyAdded, +// InvalidJsonFormat, +// ConsentNotFound, +// UnknownError +// ), +// apiTagConsent :: apiTagPSD2AIS :: Nil +// ) +// +// lazy val addConsentUser: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "consents" :: consentId :: "user-update-request" :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- SS.user +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $PutConsentUserJsonV400 " +// putJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[PutConsentUserJsonV400] +// } +// user <- Users.users.vend.getUserByUserIdFuture( +// putJson.user_id +// ) map { x => +// unboxFullOrFail( +// x, +// callContext, +// s"$UserNotFoundByUserId Current UserId(${putJson.user_id})" +// ) +// } +// consent <- Future( +// Consents.consentProvider.vend.getConsentByConsentId(consentId) +// ) map { i => +// connectorEmptyResponse(i, callContext) +// } +// _ <- Helper.booleanToFuture( +// ConsentUserAlreadyAdded, +// cc = cc.callContext +// ) { +// Option(consent.userId).forall( +// _.isBlank +// ) // checks whether userId is not populated +// } +// consent <- Future( +// Consents.consentProvider.vend.updateConsentUser(consentId, user) +// ) map { i => +// connectorEmptyResponse(i, callContext) +// } +// } yield { +// ( +// ConsentJsonV310( +// consent.consentId, +// consent.jsonWebToken, +// consent.status +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateConsentStatus, +// implementedInApiVersion, +// nameOf(updateConsentStatus), +// "PUT", +// "/banks/BANK_ID/consents/CONSENT_ID", +// "Update Consent Status", +// s""" +// | +// | +// |This endpoint is used to update the Status of Consent. +// | +// |Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted +// .mkString(", ")}. +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// PutConsentStatusJsonV400(status = "AUTHORISED"), +// ConsentChallengeJsonV310( +// consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945", +// jwt = +// "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4", +// status = "AUTHORISED" +// ), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// InvalidJsonFormat, +// InvalidConnectorResponse, +// UnknownError +// ), +// apiTagConsent :: apiTagPSD2AIS :: Nil +// ) +// +// lazy val updateConsentStatus: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "consents" :: consentId :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(user), callContext) <- SS.user +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $PutConsentStatusJsonV400 " +// consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[PutConsentStatusJsonV400] +// } +// consent <- Future( +// Consents.consentProvider.vend.getConsentByConsentId(consentId) +// ) map { i => +// connectorEmptyResponse(i, callContext) +// } +// status = ConsentStatus.withName(consentJson.status) +// (consent, code) <- APIUtil.getPropsAsBoolValue( +// "consents.sca.enabled", +// true +// ) match { +// case true => +// Future(consent, HttpCode.`202`(callContext)) +// case false => +// Future( +// Consents.consentProvider.vend +// .updateConsentStatus(consentId, status) +// ) map { i => +// connectorEmptyResponse(i, callContext) +// } map ((_, HttpCode.`200`(callContext))) +// } +// } yield { +// ( +// ConsentJsonV310( +// consent.consentId, +// consent.jsonWebToken, +// consent.status +// ), +// code +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getConsents, +// implementedInApiVersion, +// nameOf(getConsents), +// "GET", +// "/banks/BANK_ID/my/consents", +// "Get Consents", +// s""" +// | +// |This endpoint gets the Consents that the current User created. +// | +// |${userAuthenticationMessage(true)} +// | +// |1 limit (for pagination: defaults to 50) eg:limit=200 +// | +// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10 +// | +// """.stripMargin, +// EmptyBody, +// consentsJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) +// ) +// +// lazy val getConsents: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val url = cc.url +// val limitParam = getHttpRequestUrlParam(url, "limit") match { +// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50) +// case _ => 50 +// } +// val offsetParam = getHttpRequestUrlParam(url, "offset") match { +// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0) +// case _ => 0 +// } +// for { +// rows <- Future { +// DoobieConsentQueries.getConsentsByUserAndBank( +// userId = cc.userId, +// bankId = bankId.value, +// status = None, +// limit = limitParam, +// offset = offsetParam, +// sortField = "created_date", +// sortDirection = "desc" +// ) +// } +// } yield { +// val consents = rows.map(r => ConsentJsonV400( +// r.consentId, r.jwt.getOrElse(""), r.status, +// r.apiStandard.getOrElse(""), r.apiVersion.getOrElse("") +// )) +// (ConsentsJsonV400(consents), HttpCode.`200`(cc)) +// } +// } +// } +// staticResourceDocs += ResourceDoc( +// getConsentInfosByBank, +// implementedInApiVersion, +// nameOf(getConsentInfosByBank), +// "GET", +// "/banks/BANK_ID/my/consent-infos", +// "Get My Consents Info At Bank", +// s""" +// | +// |This endpoint gets the Consents that the current User created at bank. +// | +// |${userAuthenticationMessage(true)} +// | +// """.stripMargin, +// EmptyBody, +// consentInfosJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) +// ) +// +// lazy val getConsentInfosByBank: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "my" :: "consent-infos" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// consents <- Future { +// Consents.consentProvider.vend +// .getConsentsByUser(cc.userId) +// .sortBy(i => (i.creationDateTime, i.apiStandard)) +// .reverse +// } +// } yield { +// val consentsOfBank = Consent.filterByBankId(consents, bankId) +// ( +// JSONFactory400.createConsentInfosJsonV400(consentsOfBank), +// HttpCode.`200`(cc) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getConsentInfos, +// implementedInApiVersion, +// nameOf(getConsentInfos), +// "GET", +// "/my/consent-infos", +// "Get My Consents Info", +// s""" +// | +// |This endpoint gets the Consents that the current User created. +// | +// |${userAuthenticationMessage(true)} +// | +// """.stripMargin, +// EmptyBody, +// consentInfosJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2) +// ) +// +// lazy val getConsentInfos: OBPEndpoint = { +// case "my" :: "consent-infos" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// consents <- Future { +// Consents.consentProvider.vend +// .getConsentsByUser(cc.userId) +// .sortBy(i => (i.creationDateTime, i.apiStandard)) +// .reverse +// } +// } yield { +// ( +// JSONFactory400.createConsentInfosJsonV400(consents), +// HttpCode.`200`(cc) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyPersonalUserAttributes, +// implementedInApiVersion, +// nameOf(getMyPersonalUserAttributes), +// "GET", +// "/my/user/attributes", +// "Get My Personal User Attributes", +// s"""Get My Personal User Attributes. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// userAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagUser) +// ) +// +// lazy val getMyPersonalUserAttributes: OBPEndpoint = { +// case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributes, callContext) <- NewStyle.function +// .getPersonalUserAttributes(cc.userId, cc.callContext) +// } yield { +// ( +// JSONFactory400.createUserAttributesJson(attributes), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getUserWithAttributes, +// implementedInApiVersion, +// nameOf(getUserWithAttributes), +// "GET", +// "/users/USER_ID/attributes", +// "Get User with Attributes by USER_ID", +// s"""Get User Attributes for the user defined via USER_ID. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// userWithAttributesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagUser), +// Some(canGetUsersWithAttributes :: Nil) +// ) +// +// lazy val getUserWithAttributes: OBPEndpoint = { +// case "users" :: userId :: "attributes" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (user, callContext) <- NewStyle.function.getUserByUserId( +// userId, +// cc.callContext +// ) +// (attributes, callContext) <- NewStyle.function.getUserAttributes( +// user.userId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createUserWithAttributesJson(user, attributes), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createMyPersonalUserAttribute, +// implementedInApiVersion, +// nameOf(createMyPersonalUserAttribute), +// "POST", +// "/my/user/attributes", +// "Create My Personal User Attribute", +// s""" Create My Personal User Attribute +// | +// |The `type` field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// userAttributeJsonV400, +// userAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagUser), +// Some(List()) +// ) +// +// lazy val createMyPersonalUserAttribute: OBPEndpoint = { +// case "my" :: "user" :: "attributes" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val failMsg = +// s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 " +// for { +// postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { +// json.extract[UserAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${TransactionAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)" +// userAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// cc.callContext +// ) { +// UserAttributeType.withName(postedData.`type`) +// } +// (userAttribute, callContext) <- NewStyle.function +// .createOrUpdateUserAttribute( +// cc.userId, +// None, +// postedData.name, +// userAttributeType, +// postedData.value, +// true, +// cc.callContext +// ) +// } yield { +// ( +// JSONFactory400.createUserAttributeJson(userAttribute), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateMyPersonalUserAttribute, +// implementedInApiVersion, +// nameOf(updateMyPersonalUserAttribute), +// "PUT", +// "/my/user/attributes/USER_ATTRIBUTE_ID", +// "Update My Personal User Attribute", +// s"""Update My Personal User Attribute for current user by USER_ATTRIBUTE_ID +// | +// |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// userAttributeJsonV400, +// userAttributeResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagUser), +// Some(List()) +// ) +// +// lazy val updateMyPersonalUserAttribute: OBPEndpoint = { +// case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (attributes, callContext) <- NewStyle.function +// .getPersonalUserAttributes(cc.userId, cc.callContext) +// failMsg = s"$UserAttributeNotFound" +// _ <- NewStyle.function.tryons(failMsg, 400, callContext) { +// attributes.exists(_.userAttributeId == userAttributeId) +// } +// postedData <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 ", +// 400, +// callContext +// ) { +// json.extract[UserAttributeJsonV400] +// } +// failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + +// s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)" +// userAttributeType <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// UserAttributeType.withName(postedData.`type`) +// } +// (userAttribute, callContext) <- NewStyle.function +// .createOrUpdateUserAttribute( +// cc.userId, +// Some(userAttributeId), +// postedData.name, +// userAttributeType, +// postedData.value, +// true, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createUserAttributeJson(userAttribute), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getScannedApiVersions, +// implementedInApiVersion, +// nameOf(getScannedApiVersions), +// "GET", +// "/api/versions", +// "Get scanned API Versions", +// s"""Get all the scanned API Versions.""", +// EmptyBody, +// ListResult( +// "scanned_api_versions", +// List(Extraction.decompose(ApiVersion.v3_1_0)) +// ), +// List( +// UnknownError +// ), +// List(apiTagDocumentation, apiTagApi), +// Some(Nil) +// ) +// +// lazy val getScannedApiVersions: OBPEndpoint = { +// case "api" :: "versions" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// Future { +// val versions: List[ScannedApiVersion] = +// ApiVersion.allScannedApiVersion.asScala.toList.filter { version => +// version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version) +// } +// ( +// ListResult("scanned_api_versions", versions), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createMyApiCollection, +// implementedInApiVersion, +// nameOf(createMyApiCollection), +// "POST", +// "/my/api-collections", +// "Create My Api Collection", +// s"""Create Api Collection for logged in user. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// postApiCollectionJson400, +// apiCollectionJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val createMyApiCollection: OBPEndpoint = { +// case "my" :: "api-collections" :: Nil JsonPost json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionJson400", +// 400, +// cc.callContext +// ) { +// json.extract[PostApiCollectionJson400] +// } +// apiCollection <- Future { +// MappedApiCollectionsProvider +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// postJson.api_collection_name +// ) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$ApiCollectionAlreadyExists Current api_collection_name(${postJson.api_collection_name}) is already existing for the log in user.", +// cc = cc.callContext +// ) { +// apiCollection.isEmpty +// } +// (apiCollection, callContext) <- NewStyle.function.createApiCollection( +// cc.userId, +// postJson.api_collection_name, +// postJson.is_sharable, +// postJson.description.getOrElse(""), +// Some(cc) +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionJsonV400(apiCollection), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollectionByName, +// implementedInApiVersion, +// nameOf(getMyApiCollectionByName), +// "GET", +// "/my/api-collections/name/API_COLLECTION_NAME", +// "Get My Api Collection By Name", +// s"""Get Api Collection By API_COLLECTION_NAME. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollectionByName: OBPEndpoint = { +// case "my" :: "api-collections" :: "name" :: apiCollectionName :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// apiCollectionName, +// Some(cc) +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionJsonV400(apiCollection), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollectionById, +// implementedInApiVersion, +// nameOf(getMyApiCollectionById), +// "GET", +// "/my/api-collections/API_COLLECTION_ID", +// "Get My Api Collection By Id", +// s"""Get Api Collection By API_COLLECTION_ID. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollectionById: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// } yield { +// ( +// JSONFactory400.createApiCollectionJsonV400(apiCollection), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getSharableApiCollectionById, +// implementedInApiVersion, +// nameOf(getSharableApiCollectionById), +// "GET", +// "/api-collections/sharable/API_COLLECTION_ID", +// "Get Sharable Api Collection By Id", +// s"""Get Sharable Api Collection By Id. +// |${userAuthenticationMessage(false)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionJson400, +// List( +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getSharableApiCollectionById: OBPEndpoint = { +// case "api-collections" :: "sharable" :: apiCollectionId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, cc.callContext) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$ApiCollectionEndpointNotFound Current api_collection_id(${apiCollectionId}) is not sharable.", +// cc = callContext +// ) { +// apiCollection.isSharable +// } +// } yield { +// ( +// JSONFactory400.createApiCollectionJsonV400(apiCollection), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getApiCollectionsForUser, +// implementedInApiVersion, +// nameOf(getApiCollectionsForUser), +// "GET", +// "/users/USER_ID/api-collections", +// "Get Api Collections for User", +// s"""Get Api Collections for User. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionsJson400, +// List( +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection), +// Some(canGetApiCollectionsForUser :: Nil) +// ) +// +// lazy val getApiCollectionsForUser: OBPEndpoint = { +// case "users" :: userId :: "api-collections" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.findByUserId(userId, Some(cc)) +// (apiCollections, callContext) <- NewStyle.function +// .getApiCollectionsByUserId(userId, callContext) +// } yield { +// ( +// JSONFactory400.createApiCollectionsJsonV400(apiCollections), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getFeaturedApiCollections, +// implementedInApiVersion, +// nameOf(getFeaturedApiCollections), +// "GET", +// "/api-collections/featured", +// "Get Featured Api Collections", +// s"""Get Featured Api Collections. +// | +// |${userAuthenticationMessage(false)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionsJson400, +// List( +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getFeaturedApiCollections: OBPEndpoint = { +// case "api-collections" :: "featured" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollections, callContext) <- NewStyle.function +// .getFeaturedApiCollections(cc.callContext) +// } yield { +// ( +// JSONFactory400.createApiCollectionsJsonV400(apiCollections), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollections, +// implementedInApiVersion, +// nameOf(getMyApiCollections), +// "GET", +// "/my/api-collections", +// "Get My Api Collections", +// s"""Get all the apiCollections for logged in user. +// | +// |${userAuthenticationMessage(true)} +// | +// |1 limit (for pagination: defaults to 50) eg:limit=200 +// | +// |2 offset (for pagination: zero index, defaults to 0) eg: offset=10 +// | +// |""".stripMargin, +// EmptyBody, +// apiCollectionsJson400, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollections: OBPEndpoint = { +// case "my" :: "api-collections" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val url = cc.url +// val limitParam = getHttpRequestUrlParam(url, "limit") match { +// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50) +// case _ => 50 +// } +// val offsetParam = getHttpRequestUrlParam(url, "offset") match { +// case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0) +// case _ => 0 +// } +// for { +// (apiCollections, callContext) <- NewStyle.function +// .getApiCollectionsByUserId(cc.userId, Some(cc)) +// } yield { +// val paginated = apiCollections.drop(offsetParam).take(limitParam) +// ( +// JSONFactory400.createApiCollectionsJsonV400(paginated), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyApiCollection, +// implementedInApiVersion, +// nameOf(deleteMyApiCollection), +// "DELETE", +// "/my/api-collections/API_COLLECTION_ID", +// "Delete My Api Collection", +// s"""Delete Api Collection By API_COLLECTION_ID +// | +// |${Glossary.getGlossaryItem("API Collections")} +// | +// |${userAuthenticationMessage(true)} +// | +// | +// | +// |""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val deleteMyApiCollection: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// (deleted, callContext) <- NewStyle.function.deleteApiCollectionById( +// apiCollectionId, +// callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createMyApiCollectionEndpoint, +// implementedInApiVersion, +// nameOf(createMyApiCollectionEndpoint), +// "POST", +// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints", +// "Create My Api Collection Endpoint", +// s"""Create Api Collection Endpoint. +// | +// |${Glossary.getGlossaryItem("API Collections")} +// | +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// postApiCollectionEndpointJson400, +// apiCollectionEndpointJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val createMyApiCollectionEndpoint: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400", +// 400, +// cc.callContext +// ) { +// json.extract[PostApiCollectionEndpointJson400] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})", +// cc = Some(cc) +// ) { +// getAllResourceDocs +// .find(_.operationId == postJson.operation_id.trim) +// .isDefined +// } +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// apiCollectionName, +// Some(cc) +// ) +// apiCollectionEndpoint <- Future { +// MappedApiCollectionEndpointsProvider +// .getApiCollectionEndpointByApiCollectionIdAndOperationId( +// apiCollection.apiCollectionId, +// postJson.operation_id +// ) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_NAME($apiCollectionName) ", +// cc = callContext +// ) { +// apiCollectionEndpoint.isEmpty +// } +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .createApiCollectionEndpoint( +// apiCollection.apiCollectionId, +// postJson.operation_id, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointJsonV400( +// apiCollectionEndpoint +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// staticResourceDocs += ResourceDoc( +// createMyApiCollectionEndpointById, +// implementedInApiVersion, +// nameOf(createMyApiCollectionEndpointById), +// "POST", +// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints", +// "Create My Api Collection Endpoint By Id", +// s"""Create Api Collection Endpoint By Id. +// | +// |${Glossary.getGlossaryItem("API Collections")} +// | +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// postApiCollectionEndpointJson400, +// apiCollectionEndpointJson400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val createMyApiCollectionEndpointById: OBPEndpoint = { +// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// postJson <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $PostApiCollectionEndpointJson400", +// 400, +// cc.callContext +// ) { +// json.extract[PostApiCollectionEndpointJson400] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidOperationId Current OPERATION_ID(${postJson.operation_id})", +// cc = Some(cc) +// ) { +// getAllResourceDocs +// .find(_.operationId == postJson.operation_id.trim) +// .isDefined +// } +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// apiCollectionEndpoint <- Future { +// MappedApiCollectionEndpointsProvider +// .getApiCollectionEndpointByApiCollectionIdAndOperationId( +// apiCollection.apiCollectionId, +// postJson.operation_id +// ) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$ApiCollectionEndpointAlreadyExists Current OPERATION_ID(${postJson.operation_id}) is already in API_COLLECTION_ID($apiCollectionId) ", +// cc = callContext +// ) { +// apiCollectionEndpoint.isEmpty +// } +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .createApiCollectionEndpoint( +// apiCollection.apiCollectionId, +// postJson.operation_id, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointJsonV400( +// apiCollectionEndpoint +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollectionEndpoint, +// implementedInApiVersion, +// nameOf(getMyApiCollectionEndpoint), +// "GET", +// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID", +// "Get My Api Collection Endpoint", +// s"""Get Api Collection Endpoint By API_COLLECTION_NAME and OPERATION_ID. +// | +// |${userAuthenticationMessage(false)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionEndpointJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollectionEndpoint: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// apiCollectionName, +// Some(cc) +// ) +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .getApiCollectionEndpointByApiCollectionIdAndOperationId( +// apiCollection.apiCollectionId, +// operationId, +// Some(cc) +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointJsonV400( +// apiCollectionEndpoint +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getApiCollectionEndpoints, +// implementedInApiVersion, +// nameOf(getApiCollectionEndpoints), +// "GET", +// "/api-collections/API_COLLECTION_ID/api-collection-endpoints", +// "Get Api Collection Endpoints", +// s"""Get Api Collection Endpoints By API_COLLECTION_ID. +// | +// |${userAuthenticationMessage(false)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionEndpointsJson400, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getApiCollectionEndpoints: OBPEndpoint = { +// case "api-collections" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollectionEndpoints, callContext) <- NewStyle.function +// .getApiCollectionEndpoints(apiCollectionId, Some(cc)) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointsJsonV400( +// apiCollectionEndpoints +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollectionEndpoints, +// implementedInApiVersion, +// nameOf(getMyApiCollectionEndpoints), +// "GET", +// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints", +// "Get My Api Collection Endpoints", +// s"""Get Api Collection Endpoints By API_COLLECTION_NAME. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionEndpointsJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollectionEndpoints: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// apiCollectionName, +// Some(cc) +// ) +// (apiCollectionEndpoints, callContext) <- NewStyle.function +// .getApiCollectionEndpoints( +// apiCollection.apiCollectionId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointsJsonV400( +// apiCollectionEndpoints +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMyApiCollectionEndpointsById, +// implementedInApiVersion, +// nameOf(getMyApiCollectionEndpointsById), +// "GET", +// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints", +// "Get My Api Collection Endpoints By Id", +// s"""Get Api Collection Endpoints By API_COLLECTION_ID. +// | +// |${userAuthenticationMessage(true)} +// |""".stripMargin, +// EmptyBody, +// apiCollectionEndpointsJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val getMyApiCollectionEndpointsById: OBPEndpoint = { +// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// (apiCollectionEndpoints, callContext) <- NewStyle.function +// .getApiCollectionEndpoints( +// apiCollection.apiCollectionId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createApiCollectionEndpointsJsonV400( +// apiCollectionEndpoints +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyApiCollectionEndpoint, +// implementedInApiVersion, +// nameOf(deleteMyApiCollectionEndpoint), +// "DELETE", +// "/my/api-collections/API_COLLECTION_NAME/api-collection-endpoints/OPERATION_ID", +// "Delete My Api Collection Endpoint", +// s"""${Glossary.getGlossaryItem("API Collections")} +// | +// | +// |Delete Api Collection Endpoint By OPERATION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val deleteMyApiCollectionEndpoint: OBPEndpoint = { +// case "my" :: "api-collections" :: apiCollectionName :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionByUserIdAndCollectionName( +// cc.userId, +// apiCollectionName, +// Some(cc) +// ) +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .getApiCollectionEndpointByApiCollectionIdAndOperationId( +// apiCollection.apiCollectionId, +// operationId, +// callContext +// ) +// (deleted, callContext) <- NewStyle.function +// .deleteApiCollectionEndpointById( +// apiCollectionEndpoint.apiCollectionEndpointId, +// callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyApiCollectionEndpointByOperationId, +// implementedInApiVersion, +// nameOf(deleteMyApiCollectionEndpointByOperationId), +// "DELETE", +// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoints/OPERATION_ID", +// "Delete My Api Collection Endpoint By Id", +// s"""${Glossary.getGlossaryItem("API Collections")} +// | +// |Delete Api Collection Endpoint By OPERATION_ID +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val deleteMyApiCollectionEndpointByOperationId: OBPEndpoint = { +// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoints" :: operationId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .getApiCollectionEndpointByApiCollectionIdAndOperationId( +// apiCollection.apiCollectionId, +// operationId, +// callContext +// ) +// (deleted, callContext) <- NewStyle.function +// .deleteApiCollectionEndpointById( +// apiCollectionEndpoint.apiCollectionEndpointId, +// callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteMyApiCollectionEndpointById, +// implementedInApiVersion, +// nameOf(deleteMyApiCollectionEndpointById), +// "DELETE", +// "/my/api-collection-ids/API_COLLECTION_ID/api-collection-endpoint-ids/API_COLLECTION_ENDPOINT_ID", +// "Delete My Api Collection Endpoint By Id", +// s"""${Glossary.getGlossaryItem("API Collections")} +// |Delete Api Collection Endpoint +// |Delete Api Collection Endpoint By Id +// | +// |${userAuthenticationMessage(true)} +// | +// |""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// UserNotFoundByUserId, +// UnknownError +// ), +// List(apiTagApiCollection) +// ) +// +// lazy val deleteMyApiCollectionEndpointById: OBPEndpoint = { +// case "my" :: "api-collection-ids" :: apiCollectionId :: "api-collection-endpoint-ids" :: apiCollectionEndpointId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (apiCollection, callContext) <- NewStyle.function +// .getApiCollectionById(apiCollectionId, Some(cc)) +// (apiCollectionEndpoint, callContext) <- NewStyle.function +// .getApiCollectionEndpointById( +// apiCollectionEndpointId, +// callContext +// ) +// (deleted, callContext) <- NewStyle.function +// .deleteApiCollectionEndpointById( +// apiCollectionEndpoint.apiCollectionEndpointId, +// callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createJsonSchemaValidation, +// implementedInApiVersion, +// nameOf(createJsonSchemaValidation), +// "POST", +// "/management/json-schema-validations/OPERATION_ID", +// "Create a JSON Schema Validation", +// s"""Create a JSON Schema Validation. +// | +// |Introduction: +// |${Glossary.getGlossaryItemSimple("JSON Schema Validation")} +// | +// |To use this endpoint, please supply a valid json-schema in the request body. +// | +// |Note: It might take a few minutes for the newly created JSON Schema to take effect! +// |""", +// postOrPutJsonSchemaV400, +// responseJsonSchema, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// Some(List(canCreateJsonSchemaValidation)) +// ) +// +// lazy val createJsonSchemaValidation: OBPEndpoint = { +// case "management" :: "json-schema-validations" :: operationId :: Nil JsonPost _ -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val httpBody: String = cc.httpBody.getOrElse("") +// for { +// (Full(u), callContext) <- SS.user +// +// schemaErrors: util.Set[ValidationMessage] = JsonSchemaUtil +// .validateSchema(httpBody) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", +// cc = callContext +// ) { +// CommonUtil.Collections.isEmpty(schemaErrors) +// } +// +// (isExists, callContext) <- NewStyle.function +// .isJsonSchemaValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = OperationIdExistsError, +// cc = callContext +// ) { +// !isExists +// } +// (validation, callContext) <- NewStyle.function +// .createJsonSchemaValidation( +// JsonValidation(operationId, httpBody), +// callContext +// ) +// } yield { +// (validation, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateJsonSchemaValidation, +// implementedInApiVersion, +// nameOf(updateJsonSchemaValidation), +// "PUT", +// "/management/json-schema-validations/OPERATION_ID", +// "Update a JSON Schema Validation", +// s"""Update a JSON Schema Validation. +// | +// |Introduction: +// |${Glossary.getGlossaryItemSimple("JSON Schema Validation")} +// | +// |To use this endpoint, please supply a valid json-schema in the request body. +// | +// |""", +// postOrPutJsonSchemaV400, +// responseJsonSchema, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// Some(List(canUpdateJsonSchemaValidation)) +// ) +// +// lazy val updateJsonSchemaValidation: OBPEndpoint = { +// case "management" :: "json-schema-validations" :: operationId :: Nil JsonPut _ -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// val httpBody: String = cc.httpBody.getOrElse("") +// for { +// (Full(u), callContext) <- SS.user +// +// schemaErrors = JsonSchemaUtil.validateSchema(httpBody) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", +// cc = callContext +// ) { +// CommonUtil.Collections.isEmpty(schemaErrors) +// } +// +// (isExists, callContext) <- NewStyle.function +// .isJsonSchemaValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = JsonSchemaValidationNotFound, +// cc = callContext +// ) { +// isExists +// } +// (validation, callContext) <- NewStyle.function +// .updateJsonSchemaValidation(operationId, httpBody, callContext) +// } yield { +// (validation, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteJsonSchemaValidation, +// implementedInApiVersion, +// nameOf(deleteJsonSchemaValidation), +// "DELETE", +// "/management/json-schema-validations/OPERATION_ID", +// "Delete a JSON Schema Validation", +// s"""Delete a JSON Schema Validation by operation_id. +// | +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// Some(List(canDeleteJsonSchemaValidation)) +// ) +// +// lazy val deleteJsonSchemaValidation: OBPEndpoint = { +// case "management" :: "json-schema-validations" :: operationId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// +// (isExists, callContext) <- NewStyle.function +// .isJsonSchemaValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = JsonSchemaValidationNotFound, +// cc = callContext +// ) { +// isExists +// } +// +// (deleteResult, callContext) <- NewStyle.function +// .deleteJsonSchemaValidation(operationId, callContext) +// } yield { +// (deleteResult, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getJsonSchemaValidation, +// implementedInApiVersion, +// nameOf(getJsonSchemaValidation), +// "GET", +// "/management/json-schema-validations/OPERATION_ID", +// "Get a JSON Schema Validation", +// s"""Get a JSON Schema Validation by operation_id. +// | +// |""", +// EmptyBody, +// responseJsonSchema, +// List( +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// Some(List(canGetJsonSchemaValidation)) +// ) +// +// lazy val getJsonSchemaValidation: OBPEndpoint = { +// case "management" :: "json-schema-validations" :: operationId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (validation, callContext) <- NewStyle.function +// .getJsonSchemaValidationByOperationId(operationId, cc.callContext) +// } yield { +// (validation, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllJsonSchemaValidations, +// implementedInApiVersion, +// nameOf(getAllJsonSchemaValidations), +// "GET", +// "/management/json-schema-validations", +// "Get all JSON Schema Validations", +// s"""Get all JSON Schema Validations. +// | +// |""", +// EmptyBody, +// ListResult("json_schema_validations", responseJsonSchema :: Nil), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// Some(List(canGetJsonSchemaValidation)) +// ) +// +// lazy val getAllJsonSchemaValidations: OBPEndpoint = { +// case ("management" | +// "endpoints") :: "json-schema-validations" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (jsonSchemaValidations, callContext) <- NewStyle.function +// .getJsonSchemaValidations(cc.callContext) +// } yield { +// ( +// ListResult("json_schema_validations", jsonSchemaValidations), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// private val jsonSchemaValidationRequiresRole: Boolean = APIUtil +// .getPropsAsBoolValue("read_json_schema_validation_requires_role", false) +// lazy val getAllJsonSchemaValidationsPublic = getAllJsonSchemaValidations +// +// staticResourceDocs += ResourceDoc( +// getAllJsonSchemaValidationsPublic, +// implementedInApiVersion, +// nameOf(getAllJsonSchemaValidationsPublic), +// "GET", +// "/endpoints/json-schema-validations", +// "Get all JSON Schema Validations - public", +// s"""Get all JSON Schema Validations - public. +// | +// |""", +// EmptyBody, +// ListResult("json_schema_validations", responseJsonSchema :: Nil), +// (if (jsonSchemaValidationRequiresRole) List($AuthenticatedUserIsRequired) else Nil) +// ::: List( +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagJsonSchemaValidation), +// None +// ) +// +// // auth type validation related endpoints +// private val allowedAuthTypes = +// AuthenticationType.values.filterNot(AuthenticationType.Anonymous.==) +// staticResourceDocs += ResourceDoc( +// createAuthenticationTypeValidation, +// implementedInApiVersion, +// nameOf(createAuthenticationTypeValidation), +// "POST", +// "/management/authentication-type-validations/OPERATION_ID", +// "Create an Authentication Type Validation", +// s"""Create an Authentication Type Validation. +// | +// |Please supply allowed authentication types. +// |""", +// allowedAuthTypes, +// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// Some(List(canCreateAuthenticationTypeValidation)) +// ) +// +// lazy val createAuthenticationTypeValidation: OBPEndpoint = { +// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPost jArray -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// +// authTypes <- NewStyle.function.tryons( +// s"$AuthenticationTypeNameIllegal Allowed Authentication Type names: ${allowedAuthTypes +// .mkString("[", ", ", "]")}", +// 400, +// cc.callContext +// ) { +// jArray.extract[List[AuthenticationType]] +// } +// +// (isExists, callContext) <- NewStyle.function +// .isAuthenticationTypeValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = OperationIdExistsError, +// cc = callContext +// ) { +// !isExists +// } +// (authenticationTypeValidation, callContext) <- NewStyle.function +// .createAuthenticationTypeValidation( +// JsonAuthTypeValidation(operationId, authTypes), +// callContext +// ) +// } yield { +// (authenticationTypeValidation, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAuthenticationTypeValidation, +// implementedInApiVersion, +// nameOf(updateAuthenticationTypeValidation), +// "PUT", +// "/management/authentication-type-validations/OPERATION_ID", +// "Update an Authentication Type Validation", +// s"""Update an Authentication Type Validation. +// | +// |Please supply allowed authentication types. +// |""", +// allowedAuthTypes, +// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// Some(List(canUpdateAuthenticationTypeValidation)) +// ) +// +// lazy val updateAuthenticationTypeValidation: OBPEndpoint = { +// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonPut jArray -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// +// authTypes <- NewStyle.function.tryons( +// s"$AuthenticationTypeNameIllegal Allowed AuthenticationType names: ${allowedAuthTypes +// .mkString("[", ", ", "]")}", +// 400, +// cc.callContext +// ) { +// jArray.extract[List[AuthenticationType]] +// } +// +// (isExists, callContext) <- NewStyle.function +// .isAuthenticationTypeValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = AuthenticationTypeValidationNotFound, +// cc = callContext +// ) { +// isExists +// } +// (authenticationTypeValidation, callContext) <- NewStyle.function +// .updateAuthenticationTypeValidation( +// operationId, +// authTypes, +// callContext +// ) +// } yield { +// (authenticationTypeValidation, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteAuthenticationTypeValidation, +// implementedInApiVersion, +// nameOf(deleteAuthenticationTypeValidation), +// "DELETE", +// "/management/authentication-type-validations/OPERATION_ID", +// "Delete an Authentication Type Validation", +// s"""Delete an Authentication Type Validation by operation_id. +// | +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// Some(List(canDeleteAuthenticationValidation)) +// ) +// +// lazy val deleteAuthenticationTypeValidation: OBPEndpoint = { +// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// +// (isExists, callContext) <- NewStyle.function +// .isAuthenticationTypeValidationExists(operationId, callContext) +// _ <- Helper.booleanToFuture( +// failMsg = AuthenticationTypeValidationNotFound, +// cc = callContext +// ) { +// isExists +// } +// +// (deleteResult, callContext) <- NewStyle.function +// .deleteAuthenticationTypeValidation(operationId, callContext) +// } yield { +// (deleteResult, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAuthenticationTypeValidation, +// implementedInApiVersion, +// nameOf(getAuthenticationTypeValidation), +// "GET", +// "/management/authentication-type-validations/OPERATION_ID", +// "Get an Authentication Type Validation", +// s"""Get an Authentication Type Validation by operation_id. +// | +// |""", +// EmptyBody, +// JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes), +// List( +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// Some(List(canGetAuthenticationTypeValidation)) +// ) +// +// lazy val getAuthenticationTypeValidation: OBPEndpoint = { +// case "management" :: "authentication-type-validations" :: operationId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (authenticationTypeValidation, callContext) <- NewStyle.function +// .getAuthenticationTypeValidationByOperationId( +// operationId, +// cc.callContext +// ) +// } yield { +// (authenticationTypeValidation, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllAuthenticationTypeValidations, +// implementedInApiVersion, +// nameOf(getAllAuthenticationTypeValidations), +// "GET", +// "/management/authentication-type-validations", +// "Get all Authentication Type Validations", +// s"""Get all Authentication Type Validations. +// | +// |""", +// EmptyBody, +// ListResult( +// "authentication_types_validations", +// List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes)) +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// Some(List(canGetAuthenticationTypeValidation)) +// ) +// +// lazy val getAllAuthenticationTypeValidations: OBPEndpoint = { +// case ("management" | +// "endpoints") :: "authentication-type-validations" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (authenticationTypeValidations, callContext) <- NewStyle.function +// .getAuthenticationTypeValidations(cc.callContext) +// } yield { +// ( +// ListResult( +// "authentication_types_validations", +// authenticationTypeValidations +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// private val authenticationTypeValidationRequiresRole: Boolean = +// APIUtil.getPropsAsBoolValue( +// "read_authentication_type_validation_requires_role", +// false +// ) +// lazy val getAllAuthenticationTypeValidationsPublic = +// getAllAuthenticationTypeValidations +// +// staticResourceDocs += ResourceDoc( +// getAllAuthenticationTypeValidationsPublic, +// implementedInApiVersion, +// nameOf(getAllAuthenticationTypeValidationsPublic), +// "GET", +// "/endpoints/authentication-type-validations", +// "Get all Authentication Type Validations - public", +// s"""Get all Authentication Type Validations - public. +// | +// |""", +// EmptyBody, +// ListResult( +// "authentication_types_validations", +// List(JsonAuthTypeValidation("OBPv4.0.0-updateXxx", allowedAuthTypes)) +// ), +// (if (authenticationTypeValidationRequiresRole) List($AuthenticatedUserIsRequired) +// else Nil) +// ::: List( +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagAuthenticationTypeValidation), +// None +// ) +// +// staticResourceDocs += ResourceDoc( +// createConnectorMethod, +// implementedInApiVersion, +// nameOf(createConnectorMethod), +// "POST", +// "/management/connector-methods", +// "Create Connector Method", +// s"""Create an internal connector. +// | +// |The method_body is URL-encoded format String +// |""", +// jsonScalaConnectorMethod.copy(connectorMethodId = None), +// jsonScalaConnectorMethod, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagConnectorMethod), +// Some(List(canCreateConnectorMethod)) +// ) +// +// lazy val createConnectorMethod: OBPEndpoint = { +// case "management" :: "connector-methods" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// jsonConnectorMethod <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod", +// 400, +// cc.callContext +// ) { +// json.extract[JsonConnectorMethod] +// } +// +// (isExists, callContext) <- NewStyle.function +// .connectorMethodNameExists( +// jsonConnectorMethod.methodName, +// Some(cc) +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$ConnectorMethodAlreadyExists Please use a different method_name(${jsonConnectorMethod.methodName})", +// cc = callContext +// ) { +// (!isExists) +// } +// connectorMethod = InternalConnector.createFunction( +// jsonConnectorMethod.methodName, +// jsonConnectorMethod.decodedMethodBody, +// jsonConnectorMethod.programmingLang +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.head) +// (connectorMethod, callContext) <- NewStyle.function +// .createJsonConnectorMethod(jsonConnectorMethod, callContext) +// } yield { +// (connectorMethod, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateConnectorMethod, +// implementedInApiVersion, +// nameOf(updateConnectorMethod), +// "PUT", +// "/management/connector-methods/CONNECTOR_METHOD_ID", +// "Update Connector Method", +// s"""Update an internal connector. +// | +// |The method_body is URL-encoded format String +// |""", +// jsonScalaConnectorMethodMethodBody, +// jsonScalaConnectorMethod, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagConnectorMethod), +// Some(List(canUpdateConnectorMethod)) +// ) +// +// lazy val updateConnectorMethod: OBPEndpoint = { +// case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// connectorMethodBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonConnectorMethod", +// 400, +// cc.callContext +// ) { +// json.extract[JsonConnectorMethodMethodBody] +// } +// +// (cm, callContext) <- NewStyle.function.getJsonConnectorMethodById( +// connectorMethodId, +// cc.callContext +// ) +// +// connectorMethod = InternalConnector.createFunction( +// cm.methodName, +// connectorMethodBody.decodedMethodBody, +// connectorMethodBody.programmingLang +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.head) +// (connectorMethod, callContext) <- NewStyle.function +// .updateJsonConnectorMethod( +// connectorMethodId, +// connectorMethodBody.methodBody, +// connectorMethodBody.programmingLang, +// callContext +// ) +// } yield { +// (connectorMethod, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getConnectorMethod, +// implementedInApiVersion, +// nameOf(getConnectorMethod), +// "GET", +// "/management/connector-methods/CONNECTOR_METHOD_ID", +// "Get Connector Method by Id", +// s"""Get an internal connector by CONNECTOR_METHOD_ID. +// | +// |""", +// EmptyBody, +// jsonScalaConnectorMethod, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagConnectorMethod), +// Some(List(canGetConnectorMethod)) +// ) +// +// lazy val getConnectorMethod: OBPEndpoint = { +// case "management" :: "connector-methods" :: connectorMethodId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (connectorMethod, callContext) <- NewStyle.function +// .getJsonConnectorMethodById(connectorMethodId, cc.callContext) +// } yield { +// (connectorMethod, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllConnectorMethods, +// implementedInApiVersion, +// nameOf(getAllConnectorMethods), +// "GET", +// "/management/connector-methods", +// "Get all Connector Methods", +// s"""Get all Connector Methods. +// | +// |""", +// EmptyBody, +// ListResult("connectors_methods", jsonScalaConnectorMethod :: Nil), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagConnectorMethod), +// Some(List(canGetAllConnectorMethods)) +// ) +// +// lazy val getAllConnectorMethods: OBPEndpoint = { +// case "management" :: "connector-methods" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (connectorMethods, callContext) <- NewStyle.function +// .getJsonConnectorMethods(cc.callContext) +// } yield { +// ( +// ListResult("connector_methods", connectorMethods), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(createDynamicResourceDoc), +// "POST", +// "/management/dynamic-resource-docs", +// "Create Dynamic Resource Doc", +// s"""Create a Dynamic Resource Doc. +// | +// |The connector_method_body is URL-encoded format String +// |""", +// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), +// jsonDynamicResourceDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canCreateDynamicResourceDoc)) +// ) +// +// lazy val createDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// jsonDynamicResourceDoc <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicResourceDoc] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", +// cc = cc.callContext +// ) { +// Set("POST", "PUT", "GET", "DELETE").contains( +// jsonDynamicResourceDoc.requestVerb +// ) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""", +// cc = cc.callContext +// ) { +// ( +// jsonDynamicResourceDoc.requestVerb, +// jsonDynamicResourceDoc.exampleRequestBody +// ) match { +// case ( +// "GET" | "DELETE", +// Some(JString(s)) +// ) => // we support the empty string "" here +// StringUtils.isBlank(s) +// case ( +// "GET" | "DELETE", +// Some(requestBody) +// ) => // we add the guard, we forbid any json objects in GET/DELETE request body. +// requestBody == JNothing +// case _ => true +// } +// } +// _ = +// try { +// CompiledObjects( +// jsonDynamicResourceDoc.exampleRequestBody, +// jsonDynamicResourceDoc.successResponseBody, +// jsonDynamicResourceDoc.methodBody +// ) +// .validateDependency() +// } catch { +// case e: JsonResponseException => +// throw e +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// +// (isExists, callContext) <- NewStyle.function +// .isJsonDynamicResourceDocExists( +// None, +// jsonDynamicResourceDoc.requestVerb, +// jsonDynamicResourceDoc.requestUrl, +// Some(cc) +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", +// cc = callContext +// ) { +// (!isExists) +// } +// +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .createJsonDynamicResourceDoc( +// None, +// jsonDynamicResourceDoc, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(updateDynamicResourceDoc), +// "PUT", +// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Update Dynamic Resource Doc", +// s"""Update a Dynamic Resource Doc. +// | +// |The connector_method_body is URL-encoded format String +// |""", +// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), +// jsonDynamicResourceDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canUpdateDynamicResourceDoc)) +// ) +// +// lazy val updateDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicResourceDocBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicResourceDoc] +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", +// cc = cc.callContext +// ) { +// Set("POST", "PUT", "GET", "DELETE").contains( +// dynamicResourceDocBody.requestVerb +// ) +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", +// cc = cc.callContext +// ) { +// ( +// dynamicResourceDocBody.requestVerb, +// dynamicResourceDocBody.exampleRequestBody +// ) match { +// case ("GET" | "DELETE", Some(JString(s))) => +// StringUtils.isBlank(s) +// case ("GET" | "DELETE", Some(requestBody)) => +// requestBody == JNothing +// case _ => true +// } +// } +// +// _ = +// try { +// CompiledObjects( +// jsonDynamicResourceDoc.exampleRequestBody, +// jsonDynamicResourceDoc.successResponseBody, +// jsonDynamicResourceDoc.methodBody +// ) +// .validateDependency() +// } catch { +// case e: JsonResponseException => +// throw e +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// +// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( +// None, +// dynamicResourceDocId, +// cc.callContext +// ) +// +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .updateJsonDynamicResourceDoc( +// None, +// dynamicResourceDocBody.copy(dynamicResourceDocId = +// Some(dynamicResourceDocId) +// ), +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(deleteDynamicResourceDoc), +// "DELETE", +// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Delete Dynamic Resource Doc", +// s"""Delete a Dynamic Resource Doc. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canDeleteDynamicResourceDoc)) +// ) +// +// lazy val deleteDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( +// None, +// dynamicResourceDocId, +// cc.callContext +// ) +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .deleteJsonDynamicResourceDocById( +// None, +// dynamicResourceDocId, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(getDynamicResourceDoc), +// "GET", +// "/management/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Get Dynamic Resource Doc by Id", +// s"""Get a Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID. +// | +// |""", +// EmptyBody, +// jsonDynamicResourceDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canGetDynamicResourceDoc)) +// ) +// +// lazy val getDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .getJsonDynamicResourceDocById( +// None, +// dynamicResourceDocId, +// cc.callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllDynamicResourceDocs, +// implementedInApiVersion, +// nameOf(getAllDynamicResourceDocs), +// "GET", +// "/management/dynamic-resource-docs", +// "Get all Dynamic Resource Docs", +// s"""Get all Dynamic Resource Docs. +// | +// |""", +// EmptyBody, +// ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canGetAllDynamicResourceDocs)) +// ) +// +// lazy val getAllDynamicResourceDocs: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicResourceDocs, callContext) <- NewStyle.function +// .getJsonDynamicResourceDocs(None, cc.callContext) +// } yield { +// ( +// ListResult("dynamic-resource-docs", dynamicResourceDocs), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankLevelDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(createBankLevelDynamicResourceDoc), +// "POST", +// "/management/banks/BANK_ID/dynamic-resource-docs", +// "Create Bank Level Dynamic Resource Doc", +// s"""Create a Bank Level Dynamic Resource Doc. +// | +// |The connector_method_body is URL-encoded format String +// |""", +// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), +// jsonDynamicResourceDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canCreateBankLevelDynamicResourceDoc)) +// ) +// +// lazy val createBankLevelDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// jsonDynamicResourceDoc <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicResourceDoc] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", +// cc = cc.callContext +// ) { +// Set("POST", "PUT", "GET", "DELETE").contains( +// jsonDynamicResourceDoc.requestVerb +// ) +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""", +// cc = cc.callContext +// ) { +// ( +// jsonDynamicResourceDoc.requestVerb, +// jsonDynamicResourceDoc.exampleRequestBody +// ) match { +// case ( +// "GET" | "DELETE", +// Some(JString(s)) +// ) => // we support the empty string "" here +// StringUtils.isBlank(s) +// case ( +// "GET" | "DELETE", +// Some(requestBody) +// ) => // we add the guard, we forbid any json objects in GET/DELETE request body. +// requestBody == JNothing +// case _ => true +// } +// } +// _ = +// try { +// CompiledObjects( +// jsonDynamicResourceDoc.exampleRequestBody, +// jsonDynamicResourceDoc.successResponseBody, +// jsonDynamicResourceDoc.methodBody +// ) +// .validateDependency() +// } catch { +// case e: JsonResponseException => +// throw e +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// _ = +// try { +// CompiledObjects( +// jsonDynamicResourceDoc.exampleRequestBody, +// jsonDynamicResourceDoc.successResponseBody, +// jsonDynamicResourceDoc.methodBody +// ) +// } catch { +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// +// (isExists, callContext) <- NewStyle.function +// .isJsonDynamicResourceDocExists( +// Some(bankId), +// jsonDynamicResourceDoc.requestVerb, +// jsonDynamicResourceDoc.requestUrl, +// Some(cc) +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", +// cc = callContext +// ) { +// (!isExists) +// } +// +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .createJsonDynamicResourceDoc( +// Some(bankId), +// jsonDynamicResourceDoc, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankLevelDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(updateBankLevelDynamicResourceDoc), +// "PUT", +// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Update Bank Level Dynamic Resource Doc", +// s"""Update a Bank Level Dynamic Resource Doc. +// | +// |The connector_method_body is URL-encoded format String +// |""", +// jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), +// jsonDynamicResourceDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canUpdateBankLevelDynamicResourceDoc)) +// ) +// +// lazy val updateBankLevelDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicResourceDocBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicResourceDoc] +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", +// cc = cc.callContext +// ) { +// Set("POST", "PUT", "GET", "DELETE").contains( +// dynamicResourceDocBody.requestVerb +// ) +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", +// cc = cc.callContext +// ) { +// ( +// dynamicResourceDocBody.requestVerb, +// dynamicResourceDocBody.exampleRequestBody +// ) match { +// case ("GET" | "DELETE", Some(JString(s))) => +// StringUtils.isBlank(s) +// case ("GET" | "DELETE", Some(requestBody)) => +// requestBody == JNothing +// case _ => true +// } +// } +// _ = +// try { +// CompiledObjects( +// dynamicResourceDocBody.exampleRequestBody, +// dynamicResourceDocBody.successResponseBody, +// dynamicResourceDocBody.methodBody +// ) +// .validateDependency() +// } catch { +// case e: JsonResponseException => +// throw e +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// +// _ = +// try { +// CompiledObjects( +// dynamicResourceDocBody.exampleRequestBody, +// dynamicResourceDocBody.successResponseBody, +// jsonDynamicResourceDoc.methodBody +// ) +// } catch { +// case e: Exception => +// val jsonResponse = createErrorJsonResponse( +// s"$DynamicCodeCompileFail ${e.getMessage}", +// 400, +// cc.correlationId +// ) +// throw JsonResponseException(jsonResponse) +// } +// +// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( +// Some(bankId), +// dynamicResourceDocId, +// cc.callContext +// ) +// +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .updateJsonDynamicResourceDoc( +// Some(bankId), +// dynamicResourceDocBody.copy(dynamicResourceDocId = +// Some(dynamicResourceDocId) +// ), +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(deleteBankLevelDynamicResourceDoc), +// "DELETE", +// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Delete Bank Level Dynamic Resource Doc", +// s"""Delete a Bank Level Dynamic Resource Doc. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canDeleteBankLevelDynamicResourceDoc)) +// ) +// +// lazy val deleteBankLevelDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById( +// Some(bankId), +// dynamicResourceDocId, +// cc.callContext +// ) +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .deleteJsonDynamicResourceDocById( +// Some(bankId), +// dynamicResourceDocId, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelDynamicResourceDoc, +// implementedInApiVersion, +// nameOf(getBankLevelDynamicResourceDoc), +// "GET", +// "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", +// "Get Bank Level Dynamic Resource Doc by Id", +// s"""Get a Bank Level Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID. +// | +// |""", +// EmptyBody, +// jsonDynamicResourceDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canGetBankLevelDynamicResourceDoc)) +// ) +// +// lazy val getBankLevelDynamicResourceDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .getJsonDynamicResourceDocById( +// Some(bankId), +// dynamicResourceDocId, +// cc.callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllBankLevelDynamicResourceDocs, +// implementedInApiVersion, +// nameOf(getAllBankLevelDynamicResourceDocs), +// "GET", +// "/management/banks/BANK_ID/dynamic-resource-docs", +// "Get all Bank Level Dynamic Resource Docs", +// s"""Get all Bank Level Dynamic Resource Docs. +// | +// |""", +// EmptyBody, +// ListResult("dynamic-resource-docs", jsonDynamicResourceDoc :: Nil), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// Some(List(canGetAllBankLevelDynamicResourceDocs)) +// ) +// +// lazy val getAllBankLevelDynamicResourceDocs: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicResourceDocs, callContext) <- NewStyle.function +// .getJsonDynamicResourceDocs(Some(bankId), cc.callContext) +// } yield { +// ( +// ListResult("dynamic-resource-docs", dynamicResourceDocs), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// buildDynamicEndpointTemplate, +// implementedInApiVersion, +// nameOf(buildDynamicEndpointTemplate), +// "POST", +// "/management/dynamic-resource-docs/endpoint-code", +// "Create Dynamic Resource Doc endpoint code", +// s"""Create a Dynamic Resource Doc endpoint code. +// | +// |copy the response and past to ${nameOf( +// PractiseEndpoint +// )}, So you can have the benefits of +// |auto compilation and debug +// |""", +// jsonResourceDocFragment, +// jsonCodeTemplateJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicResourceDoc), +// None +// ) +// +// lazy val buildDynamicEndpointTemplate: OBPEndpoint = { +// case "management" :: "dynamic-resource-docs" :: "endpoint-code" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// resourceDocFragment <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $ResourceDocFragment", +// 400, +// cc.callContext +// ) { +// json.extract[ResourceDocFragment] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", +// cc = cc.callContext +// ) { +// Set("POST", "PUT", "GET", "DELETE").contains( +// resourceDocFragment.requestVerb +// ) +// } +// +// _ <- Helper.booleanToFuture( +// failMsg = +// s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", +// cc = cc.callContext +// ) { +// ( +// resourceDocFragment.requestVerb, +// resourceDocFragment.exampleRequestBody +// ) match { +// case ("GET" | "DELETE", Some(JString(s))) => +// StringUtils.isBlank(s) +// case ("GET" | "DELETE", Some(requestBody)) => +// requestBody == JNothing +// case _ => true +// } +// } +// +// code = DynamicEndpointCodeGenerator.buildTemplate( +// resourceDocFragment +// ) +// +// } yield { +// ( +// JsonCodeTemplateJson(URLEncoder.encode(code, "UTF-8")), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(createDynamicMessageDoc), +// "POST", +// "/management/dynamic-message-docs", +// "Create Dynamic Message Doc", +// s"""Create a Dynamic Message Doc. +// |""", +// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), +// jsonDynamicMessageDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canCreateDynamicMessageDoc)) +// ) +// +// lazy val createDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "dynamic-message-docs" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicMessageDoc <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicMessageDoc] +// } +// (dynamicMessageDocExisted, callContext) <- NewStyle.function +// .isJsonDynamicMessageDocExists( +// None, +// dynamicMessageDoc.process, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", +// cc = callContext +// ) { +// (!dynamicMessageDocExisted) +// } +// connectorMethod = DynamicConnector.createFunction( +// dynamicMessageDoc.programmingLang, +// dynamicMessageDoc.decodedMethodBody +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.orNull) +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .createJsonDynamicMessageDoc(None, dynamicMessageDoc, callContext) +// } yield { +// (dynamicMessageDoc, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankLevelDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(createBankLevelDynamicMessageDoc), +// "POST", +// "/management/banks/BANK_ID/dynamic-message-docs", +// "Create Bank Level Dynamic Message Doc", +// s"""Create a Bank Level Dynamic Message Doc. +// |""", +// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), +// jsonDynamicMessageDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canCreateBankLevelDynamicMessageDoc)) +// ) +// +// lazy val createBankLevelDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicMessageDoc <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicMessageDoc] +// } +// (dynamicMessageDocExisted, callContext) <- NewStyle.function +// .isJsonDynamicMessageDocExists( +// Some(bankId), +// dynamicMessageDoc.process, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", +// cc = callContext +// ) { +// (!dynamicMessageDocExisted) +// } +// connectorMethod = DynamicConnector.createFunction( +// dynamicMessageDoc.programmingLang, +// dynamicMessageDoc.decodedMethodBody +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture(failMsg = errorMsg, cc = callContext) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.orNull) +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .createJsonDynamicMessageDoc( +// Some(bankId), +// dynamicMessageDoc, +// callContext +// ) +// } yield { +// (dynamicMessageDoc, HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(updateDynamicMessageDoc), +// "PUT", +// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Update Dynamic Message Doc", +// s"""Update a Dynamic Message Doc. +// |""", +// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), +// jsonDynamicMessageDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canUpdateDynamicMessageDoc)) +// ) +// +// lazy val updateDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicMessageDocBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicMessageDoc] +// } +// connectorMethod = DynamicConnector.createFunction( +// dynamicMessageDocBody.programmingLang, +// dynamicMessageDocBody.decodedMethodBody +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture( +// failMsg = errorMsg, +// cc = cc.callContext +// ) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.orNull) +// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( +// None, +// dynamicMessageDocId, +// cc.callContext +// ) +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .updateJsonDynamicMessageDoc( +// None, +// dynamicMessageDocBody.copy(dynamicMessageDocId = +// Some(dynamicMessageDocId) +// ), +// callContext +// ) +// } yield { +// (dynamicMessageDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(getDynamicMessageDoc), +// "GET", +// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Get Dynamic Message Doc", +// s"""Get a Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID. +// | +// |""", +// EmptyBody, +// jsonDynamicMessageDoc, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canGetDynamicMessageDoc)) +// ) +// +// lazy val getDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .getJsonDynamicMessageDocById( +// None, +// dynamicMessageDocId, +// cc.callContext +// ) +// } yield { +// (dynamicMessageDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllDynamicMessageDocs, +// implementedInApiVersion, +// nameOf(getAllDynamicMessageDocs), +// "GET", +// "/management/dynamic-message-docs", +// "Get all Dynamic Message Docs", +// s"""Get all Dynamic Message Docs. +// | +// |""", +// EmptyBody, +// ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canGetAllDynamicMessageDocs)) +// ) +// +// lazy val getAllDynamicMessageDocs: OBPEndpoint = { +// case "management" :: "dynamic-message-docs" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicMessageDocs, callContext) <- NewStyle.function +// .getJsonDynamicMessageDocs(None, cc.callContext) +// } yield { +// ( +// ListResult("dynamic-message-docs", dynamicMessageDocs), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(deleteDynamicMessageDoc), +// "DELETE", +// "/management/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Delete Dynamic Message Doc", +// s"""Delete a Dynamic Message Doc. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canDeleteDynamicMessageDoc)) +// ) +// +// lazy val deleteDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( +// None, +// dynamicMessageDocId, +// cc.callContext +// ) +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .deleteJsonDynamicMessageDocById( +// None, +// dynamicMessageDocId, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankLevelDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(updateBankLevelDynamicMessageDoc), +// "PUT", +// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Update Bank Level Dynamic Message Doc", +// s"""Update a Bank Level Dynamic Message Doc. +// |""", +// jsonDynamicMessageDoc.copy(dynamicMessageDocId = None), +// jsonDynamicMessageDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canUpdateDynamicMessageDoc)) +// ) +// +// lazy val updateBankLevelDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// dynamicMessageDocBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", +// 400, +// cc.callContext +// ) { +// json.extract[JsonDynamicMessageDoc] +// } +// connectorMethod = DynamicConnector.createFunction( +// dynamicMessageDocBody.programmingLang, +// dynamicMessageDocBody.decodedMethodBody +// ) +// errorMsg = +// if (connectorMethod.isEmpty) +// s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" +// else "" +// _ <- Helper.booleanToFuture( +// failMsg = errorMsg, +// cc = cc.callContext +// ) { +// connectorMethod.isDefined +// } +// _ = Validation.validateDependency(connectorMethod.orNull) +// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( +// Some(bankId), +// dynamicMessageDocId, +// cc.callContext +// ) +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .updateJsonDynamicMessageDoc( +// Some(bankId), +// dynamicMessageDocBody.copy(dynamicMessageDocId = +// Some(dynamicMessageDocId) +// ), +// callContext +// ) +// } yield { +// (dynamicMessageDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(getBankLevelDynamicMessageDoc), +// "GET", +// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Get Bank Level Dynamic Message Doc", +// s"""Get a Bank Level Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID. +// | +// |""", +// EmptyBody, +// jsonDynamicMessageDoc, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canGetBankLevelDynamicMessageDoc)) +// ) +// +// lazy val getBankLevelDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicMessageDoc, callContext) <- NewStyle.function +// .getJsonDynamicMessageDocById( +// None, +// dynamicMessageDocId, +// cc.callContext +// ) +// } yield { +// (dynamicMessageDoc, HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllBankLevelDynamicMessageDocs, +// implementedInApiVersion, +// nameOf(getAllBankLevelDynamicMessageDocs), +// "GET", +// "/management/banks/BANK_ID/dynamic-message-docs", +// "Get all Bank Level Dynamic Message Docs", +// s"""Get all Bank Level Dynamic Message Docs. +// | +// |""", +// EmptyBody, +// ListResult("dynamic-message-docs", jsonDynamicMessageDoc :: Nil), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canGetAllDynamicMessageDocs)) +// ) +// +// lazy val getAllBankLevelDynamicMessageDocs: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (dynamicMessageDocs, callContext) <- NewStyle.function +// .getJsonDynamicMessageDocs(Some(bankId), cc.callContext) +// } yield { +// ( +// ListResult("dynamic-message-docs", dynamicMessageDocs), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelDynamicMessageDoc, +// implementedInApiVersion, +// nameOf(deleteBankLevelDynamicMessageDoc), +// "DELETE", +// "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", +// "Delete Bank Level Dynamic Message Doc", +// s"""Delete a Bank Level Dynamic Message Doc. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagDynamicMessageDoc), +// Some(List(canDeleteBankLevelDynamicMessageDoc)) +// ) +// +// lazy val deleteBankLevelDynamicMessageDoc: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById( +// Some(bankId), +// dynamicMessageDocId, +// cc.callContext +// ) +// (dynamicResourceDoc, callContext) <- NewStyle.function +// .deleteJsonDynamicMessageDocById( +// Some(bankId), +// dynamicMessageDocId, +// callContext +// ) +// } yield { +// (dynamicResourceDoc, HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createEndpointMapping, +// implementedInApiVersion, +// nameOf(createEndpointMapping), +// "POST", +// "/management/endpoint-mappings", +// "Create Endpoint Mapping", +// s"""Create an Endpoint Mapping. +// | +// |Note: at moment only support the dynamic endpoints +// |""", +// endpointMappingRequestBodyExample, +// endpointMappingResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canCreateEndpointMapping)) +// ) +// +// lazy val createEndpointMapping: OBPEndpoint = { +// case "management" :: "endpoint-mappings" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// createEndpointMappingMethod(None, json, cc) +// } +// } +// +// private def createEndpointMappingMethod( +// bankId: Option[String], +// json: JValue, +// cc: CallContext +// ) = { +// for { +// endpointMapping <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointMappingCommons].copy(bankId = bankId) +// } +// (endpointMapping, callContext) <- NewStyle.function +// .createOrUpdateEndpointMapping( +// bankId, +// endpointMapping.copy( +// endpointMappingId = None, +// bankId = bankId +// ), // create need to make sure, endpointMappingId is None, and bankId must be from URL. +// cc.callContext +// ) +// } yield { +// val commonsData: EndpointMappingCommons = endpointMapping +// (commonsData.toJson, HttpCode.`201`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateEndpointMapping, +// implementedInApiVersion, +// nameOf(updateEndpointMapping), +// "PUT", +// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Update Endpoint Mapping", +// s"""Update an Endpoint Mapping. +// |""", +// endpointMappingRequestBodyExample, +// endpointMappingResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canUpdateEndpointMapping)) +// ) +// +// lazy val updateEndpointMapping: OBPEndpoint = { +// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateEndpointMappingMethod(None, endpointMappingId, json, cc) +// } +// } +// +// private def updateEndpointMappingMethod( +// bankId: Option[String], +// endpointMappingId: String, +// json: JValue, +// cc: CallContext +// ) = { +// for { +// endpointMappingBody <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[EndpointMappingCommons]}", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointMappingCommons].copy(bankId = bankId) +// } +// (endpointMapping, callContext) <- NewStyle.function +// .getEndpointMappingById(bankId, endpointMappingId, cc.callContext) +// _ <- Helper.booleanToFuture( +// s"$InvalidJsonFormat operation_id has to be the same in the URL (${endpointMapping.operationId}) and Body (${endpointMappingBody.operationId}). ", +// 400, +// cc.callContext +// ) { +// endpointMapping.operationId == endpointMappingBody.operationId +// } +// (endpointMapping, callContext) <- NewStyle.function +// .createOrUpdateEndpointMapping( +// bankId, +// endpointMappingBody.copy( +// endpointMappingId = Some(endpointMappingId), +// bankId = bankId +// ), // Update must set the endpointId and BankId must be from URL +// callContext +// ) +// } yield { +// val commonsData: EndpointMappingCommons = endpointMapping +// (commonsData.toJson, HttpCode.`201`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getEndpointMapping, +// implementedInApiVersion, +// nameOf(getEndpointMapping), +// "GET", +// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Get Endpoint Mapping by Id", +// s"""Get an Endpoint Mapping by ENDPOINT_MAPPING_ID. +// | +// |""", +// EmptyBody, +// endpointMappingResponseBodyExample, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canGetEndpointMapping)) +// ) +// +// lazy val getEndpointMapping: OBPEndpoint = { +// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getEndpointMappingMethod(None, endpointMappingId, cc) +// } +// } +// +// private def getEndpointMappingMethod( +// bankId: Option[String], +// endpointMappingId: String, +// cc: CallContext +// ) = { +// for { +// (endpointMapping, callContext) <- NewStyle.function +// .getEndpointMappingById(bankId, endpointMappingId, cc.callContext) +// } yield { +// val commonsData: EndpointMappingCommons = endpointMapping +// (commonsData.toJson, HttpCode.`201`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllEndpointMappings, +// implementedInApiVersion, +// nameOf(getAllEndpointMappings), +// "GET", +// "/management/endpoint-mappings", +// "Get all Endpoint Mappings", +// s"""Get all Endpoint Mappings. +// | +// |""", +// EmptyBody, +// ListResult( +// "endpoint-mappings", +// endpointMappingResponseBodyExample :: Nil +// ), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canGetAllEndpointMappings)) +// ) +// +// lazy val getAllEndpointMappings: OBPEndpoint = { +// case "management" :: "endpoint-mappings" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// getEndpointMappingsMethod(None, cc) +// } +// } +// +// private def getEndpointMappingsMethod( +// bankId: Option[String], +// cc: CallContext +// ) = { +// for { +// (endpointMappings, callContext) <- NewStyle.function +// .getEndpointMappings(bankId, cc.callContext) +// } yield { +// val listCommons: List[EndpointMappingCommons] = endpointMappings +// ( +// ListResult("endpoint-mappings", listCommons.map(_.toJson)), +// HttpCode.`200`(callContext) +// ) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteEndpointMapping, +// implementedInApiVersion, +// nameOf(deleteEndpointMapping), +// "DELETE", +// "/management/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Delete Endpoint Mapping", +// s"""Delete a Endpoint Mapping. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canDeleteEndpointMapping)) +// ) +// +// lazy val deleteEndpointMapping: OBPEndpoint = { +// case "management" :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteEndpointMappingMethod(None, endpointMappingId, cc) +// } +// } +// +// private def deleteEndpointMappingMethod( +// bankId: Option[String], +// endpointMappingId: String, +// cc: CallContext +// ) = { +// for { +// (deleted, callContext) <- NewStyle.function.deleteEndpointMapping( +// bankId, +// endpointMappingId, +// cc.callContext +// ) +// } yield { +// (deleted, HttpCode.`200`(callContext)) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankLevelEndpointMapping, +// implementedInApiVersion, +// nameOf(createBankLevelEndpointMapping), +// "POST", +// "/management/banks/BANK_ID/endpoint-mappings", +// "Create Bank Level Endpoint Mapping", +// s"""Create an Bank Level Endpoint Mapping. +// | +// |Note: at moment only support the dynamic endpoints +// |""", +// endpointMappingRequestBodyExample, +// endpointMappingResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canCreateBankLevelEndpointMapping, canCreateEndpointMapping)) +// ) +// +// lazy val createBankLevelEndpointMapping: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// createEndpointMappingMethod(Some(bankId), json, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankLevelEndpointMapping, +// implementedInApiVersion, +// nameOf(updateBankLevelEndpointMapping), +// "PUT", +// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Update Bank Level Endpoint Mapping", +// s"""Update an Bank Level Endpoint Mapping. +// |""", +// endpointMappingRequestBodyExample, +// endpointMappingResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canUpdateBankLevelEndpointMapping, canUpdateEndpointMapping)) +// ) +// +// lazy val updateBankLevelEndpointMapping: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// updateEndpointMappingMethod(Some(bankId), endpointMappingId, json, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelEndpointMapping, +// implementedInApiVersion, +// nameOf(getBankLevelEndpointMapping), +// "GET", +// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Get Bank Level Endpoint Mapping", +// s"""Get an Bank Level Endpoint Mapping by ENDPOINT_MAPPING_ID. +// | +// |""", +// EmptyBody, +// endpointMappingResponseBodyExample, +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canGetBankLevelEndpointMapping, canGetEndpointMapping)) +// ) +// +// lazy val getBankLevelEndpointMapping: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getEndpointMappingMethod(Some(bankId), endpointMappingId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAllBankLevelEndpointMappings, +// implementedInApiVersion, +// nameOf(getAllBankLevelEndpointMappings), +// "GET", +// "/management/banks/BANK_ID/endpoint-mappings", +// "Get all Bank Level Endpoint Mappings", +// s"""Get all Bank Level Endpoint Mappings. +// | +// |""", +// EmptyBody, +// ListResult( +// "endpoint-mappings", +// endpointMappingResponseBodyExample :: Nil +// ), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canGetAllBankLevelEndpointMappings, canGetAllEndpointMappings)) +// ) +// +// lazy val getAllBankLevelEndpointMappings: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// getEndpointMappingsMethod(Some(bankId), cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelEndpointMapping, +// implementedInApiVersion, +// nameOf(deleteBankLevelEndpointMapping), +// "DELETE", +// "/management/banks/BANK_ID/endpoint-mappings/ENDPOINT_MAPPING_ID", +// "Delete Bank Level Endpoint Mapping", +// s"""Delete a Bank Level Endpoint Mapping. +// |""", +// EmptyBody, +// BooleanBody(true), +// List( +// $BankNotFound, +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagEndpointMapping), +// Some(List(canDeleteBankLevelEndpointMapping, canDeleteEndpointMapping)) +// ) +// +// lazy val deleteBankLevelEndpointMapping: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoint-mappings" :: endpointMappingId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// deleteEndpointMappingMethod(Some(bankId), endpointMappingId, cc) +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmSupportedCurrencies, +// implementedInApiVersion, +// nameOf(updateAtmSupportedCurrencies), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/supported-currencies", +// "Update ATM Supported Currencies", +// s"""Update ATM Supported Currencies. +// |""", +// supportedCurrenciesJson, +// atmSupportedCurrenciesJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmSupportedCurrencies: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "supported-currencies" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// supportedCurrencies <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedCurrenciesJson]}", +// 400, +// cc.callContext +// ) { +// json.extract[SupportedCurrenciesJson].supported_currencies +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function.updateAtmSupportedCurrencies( +// bankId, +// atmId, +// supportedCurrencies, +// cc.callContext +// ) +// } yield { +// ( +// AtmSupportedCurrenciesJson( +// atm.atmId.value, +// atm.supportedCurrencies.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmSupportedLanguages, +// implementedInApiVersion, +// nameOf(updateAtmSupportedLanguages), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/supported-languages", +// "Update ATM Supported Languages", +// s"""Update ATM Supported Languages. +// |""", +// supportedLanguagesJson, +// atmSupportedLanguagesJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmSupportedLanguages: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "supported-languages" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// supportedLanguages <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[SupportedLanguagesJson]}", +// 400, +// cc.callContext +// ) { +// json.extract[SupportedLanguagesJson].supported_languages +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function.updateAtmSupportedLanguages( +// bankId, +// atmId, +// supportedLanguages, +// cc.callContext +// ) +// } yield { +// ( +// AtmSupportedLanguagesJson( +// atm.atmId.value, +// atm.supportedLanguages.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmAccessibilityFeatures, +// implementedInApiVersion, +// nameOf(updateAtmAccessibilityFeatures), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/accessibility-features", +// "Update ATM Accessibility Features", +// s"""Update ATM Accessibility Features. +// |""", +// accessibilityFeaturesJson, +// atmAccessibilityFeaturesJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmAccessibilityFeatures: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "accessibility-features" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// accessibilityFeatures <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AccessibilityFeaturesJson]}", +// 400, +// cc.callContext +// ) { +// json.extract[AccessibilityFeaturesJson].accessibility_features +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function +// .updateAtmAccessibilityFeatures( +// bankId, +// atmId, +// accessibilityFeatures, +// cc.callContext +// ) +// } yield { +// ( +// AtmAccessibilityFeaturesJson( +// atm.atmId.value, +// atm.accessibilityFeatures.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmServices, +// implementedInApiVersion, +// nameOf(updateAtmServices), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/services", +// "Update ATM Services", +// s"""Update ATM Services. +// |""", +// atmServicesJson, +// atmServicesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmServices: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "services" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// services <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmServicesJsonV400]}", +// 400, +// cc.callContext +// ) { +// json.extract[AtmServicesJsonV400].services +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function.updateAtmServices( +// bankId, +// atmId, +// services, +// cc.callContext +// ) +// } yield { +// ( +// AtmServicesResponseJsonV400( +// atm.atmId.value, +// atm.services.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmNotes, +// implementedInApiVersion, +// nameOf(updateAtmNotes), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/notes", +// "Update ATM Notes", +// s"""Update ATM Notes. +// |""", +// atmNotesJson, +// atmNotesResponseJson, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmNotes: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "notes" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// notes <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmNotesJsonV400]}", +// 400, +// cc.callContext +// ) { +// json.extract[AtmNotesJsonV400].notes +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function.updateAtmNotes( +// bankId, +// atmId, +// notes, +// cc.callContext +// ) +// } yield { +// ( +// AtmServicesResponseJsonV400( +// atm.atmId.value, +// atm.notes.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtmLocationCategories, +// implementedInApiVersion, +// nameOf(updateAtmLocationCategories), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID/location-categories", +// "Update ATM Location Categories", +// s"""Update ATM Location Categories. +// |""", +// atmLocationCategoriesJsonV400, +// atmLocationCategoriesResponseJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// +// lazy val updateAtmLocationCategories: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: "location-categories" :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// locationCategories <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmLocationCategoriesJsonV400]}", +// 400, +// cc.callContext +// ) { +// json.extract[AtmLocationCategoriesJsonV400].location_categories +// } +// (_, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (atm, callContext) <- NewStyle.function.updateAtmLocationCategories( +// bankId, +// atmId, +// locationCategories, +// cc.callContext +// ) +// } yield { +// ( +// AtmLocationCategoriesResponseJsonV400( +// atm.atmId.value, +// atm.locationCategories.getOrElse(Nil) +// ), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createAtm, +// implementedInApiVersion, +// nameOf(createAtm), +// "POST", +// "/banks/BANK_ID/atms", +// "Create ATM", +// s"""Create ATM.""", +// atmJsonV400, +// atmJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM), +// Some(List(canCreateAtm, canCreateAtmAtAnyBank)) +// ) +// lazy val createAtm: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// atmJsonV400 <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}", +// 400, +// cc.callContext +// ) { +// val atm = json.extract[AtmJsonV400] +// // Make sure the Create contains proper ATM ID +// atm.id.get +// atm +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", +// 400, +// cc.callContext +// ) { atmJsonV400.bank_id == bankId.value } +// atm <- NewStyle.function.tryons( +// ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm", +// 400, +// cc.callContext +// ) { +// JSONFactory400.transformToAtmFromV400(atmJsonV400) +// } +// (atm, callContext) <- NewStyle.function.createOrUpdateAtm( +// atm, +// cc.callContext +// ) +// } yield { +// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateAtm, +// implementedInApiVersion, +// nameOf(updateAtm), +// "PUT", +// "/banks/BANK_ID/atms/ATM_ID", +// "UPDATE ATM", +// s"""Update ATM.""", +// atmJsonV400.copy(id = None), +// atmJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM), +// Some(List(canUpdateAtm, canUpdateAtmAtAnyBank)) +// ) +// lazy val updateAtm: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (atm, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// atmJsonV400 <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV400]}", +// 400, +// cc.callContext +// ) { +// json.extract[AtmJsonV400] +// } +// _ <- Helper.booleanToFuture( +// s"$InvalidJsonValue BANK_ID has to be the same in the URL and Body", +// 400, +// cc.callContext +// ) { atmJsonV400.bank_id == bankId.value } +// atm <- NewStyle.function.tryons( +// ErrorMessages.CouldNotTransformJsonToInternalModel + " Atm", +// 400, +// cc.callContext +// ) { +// JSONFactory400.transformToAtmFromV400( +// atmJsonV400.copy(id = Some(atmId.value)) +// ) +// } +// (atm, callContext) <- NewStyle.function.createOrUpdateAtm( +// atm, +// cc.callContext +// ) +// } yield { +// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`201`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteAtm, +// implementedInApiVersion, +// nameOf(deleteAtm), +// "DELETE", +// "/banks/BANK_ID/atms/ATM_ID", +// "Delete ATM", +// s"""Delete ATM.""", +// EmptyBody, +// EmptyBody, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagATM), +// Some(List(canDeleteAtmAtAnyBank, canDeleteAtm)) +// ) +// lazy val deleteAtm: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: Nil JsonDelete _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (atm, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// cc.callContext +// ) +// (deleted, callContext) <- NewStyle.function.deleteAtm( +// atm, +// callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAtms, +// implementedInApiVersion, +// nameOf(getAtms), +// "GET", +// "/banks/BANK_ID/atms", +// "Get Bank ATMS", +// s"""Returns information about ATMs for a single bank specified by BANK_ID including: +// | +// |* Address +// |* Geo Location +// |* License the data under this endpoint is released under +// | +// |Pagination: +// | +// |By default, 100 records are returned. +// | +// |You can use the url query parameters *limit* and *offset* for pagination +// | +// |${userAuthenticationMessage(!getAtmsIsPublic)}""".stripMargin, +// EmptyBody, +// atmsJsonV400, +// List( +// $BankNotFound, +// UnknownError +// ), +// List(apiTagATM) +// ) +// lazy val getAtms: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// val limit = ObpS.param("limit") +// val offset = ObpS.param("offset") +// for { +// (_, callContext) <- getAtmsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// _ <- Helper.booleanToFuture( +// failMsg = s"${InvalidNumber} limit:${limit.getOrElse("")}", +// cc = callContext +// ) { +// limit match { +// case Full(i) => i.toList.forall(c => Character.isDigit(c) == true) +// case _ => true +// } +// } +// _ <- Helper.booleanToFuture( +// failMsg = maximumLimitExceeded, +// cc = callContext +// ) { +// limit match { +// case Full(i) if i.toInt > 10000 => false +// case _ => true +// } +// } +// (atms, callContext) <- NewStyle.function.getAtmsByBankId( +// bankId, +// offset, +// limit, +// cc.callContext +// ) +// } yield { +// (JSONFactory400.createAtmsJsonV400(atms), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getAtm, +// implementedInApiVersion, +// nameOf(getAtm), +// "GET", +// "/banks/BANK_ID/atms/ATM_ID", +// "Get Bank ATM", +// s"""Returns information about ATM for a single bank specified by BANK_ID and ATM_ID including: +// | +// |* Address +// |* Geo Location +// |* License the data under this endpoint is released under +// |${userAuthenticationMessage(!getAtmsIsPublic)} +// |""".stripMargin, +// EmptyBody, +// atmJsonV400, +// List( +// $AuthenticatedUserIsRequired, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagATM) +// ) +// lazy val getAtm: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "atms" :: AtmId( +// atmId +// ) :: Nil JsonGet req => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- getAtmsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// (atm, callContext) <- NewStyle.function.getAtm( +// bankId, +// atmId, +// callContext +// ) +// } yield { +// (JSONFactory400.createAtmJsonV400(atm), HttpCode.`200`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createSystemLevelEndpointTag, +// implementedInApiVersion, +// nameOf(createSystemLevelEndpointTag), +// "POST", +// "/management/endpoints/OPERATION_ID/tags", +// "Create System Level Endpoint Tag", +// s"""Create System Level Endpoint Tag +// | +// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds +// | +// |""".stripMargin, +// endpointTagJson400, +// bankLevelEndpointTagResponseJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canCreateSystemLevelEndpointTag)) +// ) +// lazy val createSystemLevelEndpointTag: OBPEndpoint = { +// case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// endpointTag <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointTagJson400] +// } +// (endpointTagExisted, callContext) <- NewStyle.function +// .checkSystemLevelEndpointTagExists( +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})", +// cc = callContext +// ) { +// (!endpointTagExisted) +// } +// (endpointTag, callContext) <- NewStyle.function +// .createSystemLevelEndpointTag( +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// } yield { +// ( +// SystemLevelEndpointTagResponseJson400( +// endpointTag.endpointTagId.getOrElse(""), +// endpointTag.operationId, +// endpointTag.tagName +// ), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateSystemLevelEndpointTag, +// implementedInApiVersion, +// nameOf(updateSystemLevelEndpointTag), +// "PUT", +// "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", +// "Update System Level Endpoint Tag", +// s"""Update System Level Endpoint Tag, you can only update the tag_name here, operation_id can not be updated. +// | +// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds +// | +// |""".stripMargin, +// endpointTagJson400, +// bankLevelEndpointTagResponseJson400, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// EndpointTagNotFoundByEndpointTagId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canUpdateSystemLevelEndpointTag)) +// ) +// lazy val updateSystemLevelEndpointTag: OBPEndpoint = { +// case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// endpointTag <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointTagJson400] +// } +// (_, callContext) <- NewStyle.function.getEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// (endpointTagExisted, callContext) <- NewStyle.function +// .checkSystemLevelEndpointTagExists( +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name", +// cc = callContext +// ) { +// (!endpointTagExisted) +// } +// (endpointTagT, callContext) <- NewStyle.function +// .updateSystemLevelEndpointTag( +// endpointTagId, +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// } yield { +// ( +// SystemLevelEndpointTagResponseJson400( +// endpointTagT.endpointTagId.getOrElse(""), +// endpointTagT.operationId, +// endpointTagT.tagName +// ), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getSystemLevelEndpointTags, +// implementedInApiVersion, +// nameOf(getSystemLevelEndpointTags), +// "GET", +// "/management/endpoints/OPERATION_ID/tags", +// "Get System Level Endpoint Tags", +// s"""Get System Level Endpoint Tags.""", +// EmptyBody, +// bankLevelEndpointTagResponseJson400 :: Nil, +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canGetSystemLevelEndpointTag)) +// ) +// lazy val getSystemLevelEndpointTags: OBPEndpoint = { +// case "management" :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (endpointTags, callContext) <- NewStyle.function +// .getSystemLevelEndpointTags(operationId, cc.callContext) +// } yield { +// ( +// endpointTags.map(endpointTagT => +// SystemLevelEndpointTagResponseJson400( +// endpointTagT.endpointTagId.getOrElse(""), +// endpointTagT.operationId, +// endpointTagT.tagName +// ) +// ), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteSystemLevelEndpointTag, +// implementedInApiVersion, +// nameOf(deleteSystemLevelEndpointTag), +// "DELETE", +// "/management/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", +// "Delete System Level Endpoint Tag", +// s"""Delete System Level Endpoint Tag.""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canDeleteSystemLevelEndpointTag)) +// ) +// lazy val deleteSystemLevelEndpointTag: OBPEndpoint = { +// case "management" :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// +// (deleted, callContext) <- NewStyle.function.deleteEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankLevelEndpointTag, +// implementedInApiVersion, +// nameOf(createBankLevelEndpointTag), +// "POST", +// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags", +// "Create Bank Level Endpoint Tag", +// s"""Create Bank Level Endpoint Tag +// | +// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds +// | +// | +// |""".stripMargin, +// endpointTagJson400, +// bankLevelEndpointTagResponseJson400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canCreateBankLevelEndpointTag)) +// ) +// lazy val createBankLevelEndpointTag: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// endpointTag <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointTagJson400] +// } +// (endpointTagExisted, callContext) <- NewStyle.function +// .checkBankLevelEndpointTagExists( +// bankId, +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$EndpointTagAlreadyExists OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name})", +// cc = callContext +// ) { +// (!endpointTagExisted) +// } +// (endpointTagT, callContext) <- NewStyle.function +// .createBankLevelEndpointTag( +// bankId, +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// } yield { +// ( +// BankLevelEndpointTagResponseJson400( +// endpointTagT.bankId.getOrElse(""), +// endpointTagT.endpointTagId.getOrElse(""), +// endpointTagT.operationId, +// endpointTagT.tagName +// ), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// updateBankLevelEndpointTag, +// implementedInApiVersion, +// nameOf(updateBankLevelEndpointTag), +// "PUT", +// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", +// "Update Bank Level Endpoint Tag", +// s"""Update Endpoint Tag, you can only update the tag_name here, operation_id can not be updated. +// | +// |Note: Resource Docs are cached, TTL is ${CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL} seconds +// | +// |""".stripMargin, +// endpointTagJson400, +// bankLevelEndpointTagResponseJson400, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// EndpointTagNotFoundByEndpointTagId, +// InvalidJsonFormat, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canUpdateBankLevelEndpointTag)) +// ) +// lazy val updateBankLevelEndpointTag: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonPut json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// endpointTag <- NewStyle.function.tryons( +// s"$InvalidJsonFormat The Json body should be the $EndpointTagJson400", +// 400, +// cc.callContext +// ) { +// json.extract[EndpointTagJson400] +// } +// (_, callContext) <- NewStyle.function.getEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// (endpointTagExisted, callContext) <- NewStyle.function +// .checkBankLevelEndpointTagExists( +// bankId, +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$EndpointTagAlreadyExists BANK_ID($bankId), OPERATION_ID ($operationId) and tag_name(${endpointTag.tag_name}), please choose another tag_name", +// cc = callContext +// ) { +// (!endpointTagExisted) +// } +// (endpointTagT, callContext) <- NewStyle.function +// .updateBankLevelEndpointTag( +// bankId, +// endpointTagId, +// operationId, +// endpointTag.tag_name, +// cc.callContext +// ) +// } yield { +// ( +// BankLevelEndpointTagResponseJson400( +// endpointTagT.bankId.getOrElse(""), +// endpointTagT.endpointTagId.getOrElse(""), +// endpointTagT.operationId, +// endpointTagT.tagName +// ), +// HttpCode.`201`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getBankLevelEndpointTags, +// implementedInApiVersion, +// nameOf(getBankLevelEndpointTags), +// "GET", +// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags", +// "Get Bank Level Endpoint Tags", +// s"""Get Bank Level Endpoint Tags.""", +// EmptyBody, +// bankLevelEndpointTagResponseJson400 :: Nil, +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canGetBankLevelEndpointTag)) +// ) +// lazy val getBankLevelEndpointTags: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: Nil JsonGet _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (endpointTags, callContext) <- NewStyle.function +// .getBankLevelEndpointTags(bankId, operationId, cc.callContext) +// } yield { +// ( +// endpointTags.map(endpointTagT => +// BankLevelEndpointTagResponseJson400( +// endpointTagT.bankId.getOrElse(""), +// endpointTagT.endpointTagId.getOrElse(""), +// endpointTagT.operationId, +// endpointTagT.tagName +// ) +// ), +// HttpCode.`200`(cc.callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// deleteBankLevelEndpointTag, +// implementedInApiVersion, +// nameOf(deleteBankLevelEndpointTag), +// "DELETE", +// "/management/banks/BANK_ID/endpoints/OPERATION_ID/tags/ENDPOINT_TAG_ID", +// "Delete Bank Level Endpoint Tag", +// s"""Delete Bank Level Endpoint Tag.""", +// EmptyBody, +// Full(true), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagApi), +// Some(List(canDeleteBankLevelEndpointTag)) +// ) +// lazy val deleteBankLevelEndpointTag: OBPEndpoint = { +// case "management" :: "banks" :: bankId :: "endpoints" :: operationId :: "tags" :: endpointTagId :: Nil JsonDelete _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- NewStyle.function.getEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// +// (deleted, callContext) <- NewStyle.function.deleteEndpointTag( +// endpointTagId, +// cc.callContext +// ) +// } yield { +// (Full(deleted), HttpCode.`204`(callContext)) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getMySpaces, +// implementedInApiVersion, +// nameOf(getMySpaces), +// "GET", +// "/my/spaces", +// "Get My Spaces", +// s"""Get My Spaces.""", +// EmptyBody, +// mySpaces, +// List( +// $AuthenticatedUserIsRequired, +// UnknownError +// ), +// List(apiTagUser) +// ) +// lazy val getMySpaces: OBPEndpoint = { +// case "my" :: "spaces" :: Nil JsonGet _ => { cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// entitlements <- NewStyle.function.getEntitlementsByUserId( +// u.userId, +// callContext +// ) +// } yield { +// ( +// MySpaces( +// entitlements +// .filter( +// _.roleName == canReadDynamicResourceDocsAtOneBank.toString() +// ) +// .map(entitlement => entitlement.bankId) +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProducts, +// implementedInApiVersion, +// "getProducts", +// "GET", +// "/banks/BANK_ID/products", +// "Get Products", +// s"""Returns information about the financial products offered by a bank specified by BANK_ID including: +// | +// |* Name +// |* Code +// |* Parent Product Code +// |* More info URL +// |* Terms And Conditions URL +// |* Description +// |* Terms and Conditions +// |* License the data under this endpoint is released under +// | +// |The combination of bank_id and product_code is unique. +// | +// |Can filter with attributes name and values. +// |URL params example: /banks/some-bank-id/products?&limit=50&offset=1 +// | +// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, +// EmptyBody, +// productsJsonV400, +// List( +// AuthenticatedUserIsRequired, +// BankNotFound, +// UnknownError +// ), +// List(apiTagProduct) +// ) +// lazy val getProducts: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "products" :: Nil JsonGet req => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- getProductsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// (_, callContext) <- NewStyle.function.getBank(bankId, callContext) +// params = req.params.toList.map(kv => GetProductsParam(kv._1, kv._2)) +// (products, callContext) <- NewStyle.function.getProducts( +// bankId, +// params, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createProductsJson(products), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// 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 +// | +// | +// |${userAuthenticationMessage(true)} +// | +// | +// |""", +// putProductJsonV400, +// productJsonV400.copy(attributes = None, fees = None), +// List( +// $AuthenticatedUserIsRequired, +// $BankNotFound, +// UserHasMissingRoles, +// UnknownError +// ), +// List(apiTagProduct), +// Some(List(canCreateProduct, canCreateProductAtAnyBank)) +// ) +// lazy val createProduct: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "products" :: ProductCode( +// productCode +// ) :: Nil JsonPut json -> _ => { cc => +// implicit val ec = EndpointContext(Some(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[PutProductJsonV400] +// } +// (parentProduct, callContext) <- +// product.parent_product_code.trim.nonEmpty match { +// case false => +// Future((Empty, callContext)) +// case true => +// NewStyle.function +// .getProduct( +// bankId, +// ProductCode(product.parent_product_code), +// callContext +// ) +// .map(product => (Full(product._1), product._2)) +// } +// (success, callContext) <- NewStyle.function.createOrUpdateProduct( +// bankId = bankId.value, +// code = productCode.value, +// parentProductCode = parentProduct.map(_.code.value).toOption, +// name = product.name, +// category = null, +// family = null, +// superFamily = null, +// moreInfoUrl = product.more_info_url, +// termsAndConditionsUrl = product.terms_and_conditions_url, +// details = null, +// description = product.description, +// metaLicenceId = product.meta.license.id, +// metaLicenceName = product.meta.license.name, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createProductJson(success), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getProduct, +// implementedInApiVersion, +// nameOf(getProduct), +// "GET", +// "/banks/BANK_ID/products/PRODUCT_CODE", +// "Get Bank Product", +// s"""Returns information about a financial Product offered by the bank specified by BANK_ID and PRODUCT_CODE including: +// | +// |* Name +// |* Code +// |* Parent Product Code +// |* More info URL +// |* Description +// |* Terms and Conditions +// |* Description +// |* Meta +// |* Attributes +// |* Fees +// | +// |The combination of bank_id and product_code is unique. +// | +// |${userAuthenticationMessage(!getProductsIsPublic)}""".stripMargin, +// EmptyBody, +// productJsonV400, +// List( +// AuthenticatedUserIsRequired, +// $BankNotFound, +// ProductNotFoundByProductCode, +// UnknownError +// ), +// List(apiTagProduct) +// ) +// +// lazy val getProduct: OBPEndpoint = { +// case "banks" :: BankId(bankId) :: "products" :: ProductCode( +// productCode +// ) :: Nil JsonGet _ => { cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (_, callContext) <- getProductsIsPublic match { +// case false => authenticatedAccess(cc) +// case true => anonymousAccess(cc) +// } +// (product, callContext) <- NewStyle.function.getProduct( +// bankId, +// productCode, +// callContext +// ) +// (productAttributes, callContext) <- NewStyle.function +// .getProductAttributesByBankAndCode( +// bankId, +// productCode, +// callContext +// ) +// +// (productFees, callContext) <- NewStyle.function +// .getProductFeesFromProvider(bankId, productCode, callContext) +// +// } yield { +// ( +// JSONFactory400.createProductJson( +// product, +// productAttributes, +// productFees +// ), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createCustomerMessage, +// implementedInApiVersion, +// nameOf(createCustomerMessage), +// "POST", +// "/banks/BANK_ID/customers/CUSTOMER_ID/messages", +// "Create Customer Message", +// s""" +// |Create a message for the customer specified by CUSTOMER_ID +// |${userAuthenticationMessage(true)} +// | +// |""".stripMargin, +// createMessageJsonV400, +// successMessage, +// List( +// AuthenticatedUserIsRequired, +// $BankNotFound +// ), +// List(apiTagMessage, apiTagCustomer, apiTagPerson), +// Some(List(canCreateCustomerMessage)) +// ) +// +// lazy val createCustomerMessage: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "customers" :: customerId :: "messages" :: Nil JsonPost json -> _ => { +// cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $CreateMessageJsonV400 " +// postedData <- NewStyle.function.tryons( +// failMsg, +// 400, +// callContext +// ) { +// json.extract[CreateMessageJsonV400] +// } +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, callContext) +// (_, callContext) <- NewStyle.function.createCustomerMessage( +// customer, +// bankId, +// postedData.transport, +// postedData.message, +// postedData.from_department, +// postedData.from_person, +// callContext +// ) +// } yield { +// (successMessage, HttpCode.`201`(callContext)) +// } +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// getCustomerMessages, +// implementedInApiVersion, +// nameOf(getCustomerMessages), +// "GET", +// "/banks/BANK_ID/customers/CUSTOMER_ID/messages", +// "Get Customer Messages for a Customer", +// s"""Get messages for the customer specified by CUSTOMER_ID +// ${userAuthenticationMessage(true)} +// """, +// EmptyBody, +// customerMessagesJsonV400, +// List(AuthenticatedUserIsRequired, $BankNotFound, UnknownError), +// List(apiTagMessage, apiTagCustomer), +// Some(List(canGetCustomerMessages)) +// ) +// +// lazy val getCustomerMessages: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "customers" :: customerId :: "messages" :: Nil JsonGet _ => { +// cc => +// { +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- SS.user +// (customer, callContext) <- NewStyle.function +// .getCustomerByCustomerId(customerId, callContext) +// (messages, callContext) <- NewStyle.function.getCustomerMessages( +// customer, +// bankId, +// callContext +// ) +// } yield { +// ( +// JSONFactory400.createCustomerMessagesJson(messages), +// HttpCode.`200`(callContext) +// ) +// } +// } +// } +// } +// +// val generalWebHookInfo = s""" +// |Webhooks are used to call external web services when certain events happen. +// | +// |For instance, a webhook can be used to notify an external service if a transaction is created on an account. +// | +// |""" +// +// val accountNotificationWebhookInfo = s""" +// |When an account notification webhook fires it will POST to the URL you specify during the creation of the webhook. +// | +// |Inside the payload you will find account_id and transaction_id and also user_ids and customer_ids of the Users / Customers linked to the Account. +// | | +// |The webhook will POST the following structure to your service: +// | +// |{ +// | "event_name": "OnCreateTransaction", +// | "event_id": "9ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", +// | "bank_id": "gh.29.uk", +// | "account_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", +// | "transaction_id": "7ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", +// | "related_entities": [ +// | { +// | "user_id": "8ca9a7e4-6d02-40e3-a129-0b2bf89de9b1", +// | "customer_ids": ["3ca9a7e4-6d02-40e3-a129-0b2bf89de9b1"] +// | } +// | ] +// |} +// | +// |Thus, your service should accept the above POST body structure. +// | +// |In this way, your web service can be informed about an event on an account and act accordingly. +// | +// |Further information about the account, transaction or related entities can then be retrieved using the standard REST APIs. +// |""" +// +// staticResourceDocs += ResourceDoc( +// createSystemAccountNotificationWebhook, +// implementedInApiVersion, +// nameOf(createSystemAccountNotificationWebhook), +// "POST", +// "/web-hooks/account/notifications/on-create-transaction", +// "Create system level Account Notification Webhook", +// s""" +// |Create a notification Webhook that will fire for all accounts on the system. +// | +// |$generalWebHookInfo +// | +// |$accountNotificationWebhookInfo +// | +// |""", +// accountNotificationWebhookPostJson, +// systemAccountNotificationWebhookJson, +// List(UnknownError), +// apiTagWebhook :: apiTagBank :: Nil, +// Some(List(canCreateSystemAccountNotificationWebhook)) +// ) +// +// lazy val createSystemAccountNotificationWebhook: OBPEndpoint = { +// case "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson " +// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[AccountNotificationWebhookPostJson] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})", +// cc = callContext +// ) { +// postJson.http_method.equals("POST") +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})", +// cc = callContext +// ) { +// postJson.http_protocol.equals("HTTP/1.1") +// } +// onCreateTransaction = ApiTrigger.onCreateTransaction.toString() +// wh <- +// SystemAccountNotificationWebhookTrait.systemAccountNotificationWebhook.vend +// .createSystemAccountNotificationWebhookFuture( +// userId = u.userId, +// triggerName = onCreateTransaction, +// url = postJson.url, +// httpMethod = postJson.http_method, +// httpProtocol = postJson.http_protocol +// ) map { +// unboxFullOrFail(_, callContext, CreateWebhookError) +// } +// } yield { +// ( +// createSystemLevelAccountWebhookJsonV400(wh), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// staticResourceDocs += ResourceDoc( +// createBankAccountNotificationWebhook, +// implementedInApiVersion, +// nameOf(createBankAccountNotificationWebhook), +// "POST", +// "/banks/BANK_ID/web-hooks/account/notifications/on-create-transaction", +// "Create bank level Account Notification Webhook", +// s"""Create a notification Webhook that will fire for all accounts on the specified Bank. +// | +// |$generalWebHookInfo +// | +// |$accountNotificationWebhookInfo +// | +// |""", +// accountNotificationWebhookPostJson, +// bankAccountNotificationWebhookJson, +// List( +// AuthenticatedUserIsRequired, +// $BankNotFound, +// UnknownError +// ), +// apiTagWebhook :: apiTagBank :: Nil, +// Some(List(canCreateAccountNotificationWebhookAtOneBank)) +// ) +// +// lazy val createBankAccountNotificationWebhook: OBPEndpoint = { +// case "banks" :: BankId( +// bankId +// ) :: "web-hooks" :: "account" :: "notifications" :: "on-create-transaction" :: Nil JsonPost json -> _ => { +// cc => +// implicit val ec = EndpointContext(Some(cc)) +// for { +// (Full(u), callContext) <- authenticatedAccess(cc) +// failMsg = +// s"$InvalidJsonFormat The Json body should be the $AccountNotificationWebhookPostJson " +// postJson <- NewStyle.function.tryons(failMsg, 400, callContext) { +// json.extract[AccountNotificationWebhookPostJson] +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidHttpMethod Only Support `POST` currently. Current value is (${postJson.http_method})", +// cc = callContext +// ) { +// postJson.http_method.equals("POST") +// } +// _ <- Helper.booleanToFuture( +// failMsg = +// s"$InvalidHttpProtocol Only Support `HTTP/1.1` currently. Current value is (${postJson.http_protocol})", +// cc = callContext +// ) { +// postJson.http_protocol.equals("HTTP/1.1") +// } +// onCreateTransaction = ApiTrigger.onCreateTransaction.toString() +// wh <- +// BankAccountNotificationWebhookTrait.bankAccountNotificationWebhook.vend +// .createBankAccountNotificationWebhookFuture( +// bankId = bankId.value, +// userId = u.userId, +// triggerName = onCreateTransaction, +// url = postJson.url, +// httpMethod = postJson.http_method, +// httpProtocol = postJson.http_protocol +// ) map { +// unboxFullOrFail(_, callContext, CreateWebhookError) +// } +// } yield { +// ( +// createBankLevelAccountWebhookJsonV400(wh), +// HttpCode.`201`(callContext) +// ) +// } +// } +// } +// +// } +// +// private def checkRoleBankIdExsiting( +// callContext: Option[CallContext], +// entitlement: CreateEntitlementJSON +// ) = { +// Helper.booleanToFuture( +// failMsg = s"$BankNotFound Current BANK_ID (${entitlement.bank_id})", +// cc = callContext +// ) { +// entitlement.bank_id.nonEmpty == false || BankX( +// BankId(entitlement.bank_id), +// callContext +// ).map(_._1).isEmpty == false +// } +// } +// +// private def checkRolesBankIdExsiting( +// callContext: Option[CallContext], +// postedData: PostCreateUserWithRolesJsonV400 +// ) = { +// Future.sequence( +// postedData.roles.map(checkRoleBankIdExsiting(callContext, _)) +// ) +// } +// +// private def addEntitlementToUser( +// userId: String, +// entitlement: CreateEntitlementJSON, +// callContext: Option[CallContext] +// ) = { +// Future( +// Entitlement.entitlement.vend +// .addEntitlement(entitlement.bank_id, userId, entitlement.role_name) +// ) map { unboxFull(_) } +// } +// +// private def addEntitlementsToUser( +// userId: String, +// postedData: PostCreateUserWithRolesJsonV400, +// callContext: Option[CallContext] +// ) = { +// Future.sequence( +// postedData.roles.distinct.map( +// addEntitlementToUser(userId, _, callContext) +// ) +// ) +// } +// +// /** This method will check all the roles the request user already has and the +// * request roles: It will find the roles the requestUser already have, then +// * show the error to the developer. (We can not grant the same roles to the +// * request user twice) +// */ +// private def assertTargetUserLacksRoles( +// userId: String, +// requestedEntitlements: List[CreateEntitlementJSON], +// callContext: Option[CallContext] +// ) = { +// // 1st: get all the entitlements for the user: +// val userEntitlements = +// Entitlement.entitlement.vend.getEntitlementsByUserId(userId) +// val userRoles = userEntitlements +// .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId))) +// .getOrElse(List.empty[(String, String)]) +// .toSet +// +// val targetRoles = requestedEntitlements +// .map(entitlement => (entitlement.role_name, entitlement.bank_id)) +// .toSet +// +// // 2rd: find the duplicated ones: +// val duplicatedRoles = userRoles.filter(targetRoles) +// +// // 3rd: We can not grant the roles again, so we show the error to the developer. +// if (duplicatedRoles.size > 0) { +// val errorMessages = +// s"$EntitlementAlreadyExists user_id($userId) ${duplicatedRoles.mkString(",")}" +// Helper.booleanToFuture(errorMessages, cc = callContext) { false } +// } else +// Future.successful(Full(())) +// } +// +// /** This method will check all the roles the loggedIn user already has and the +// * request roles: It will find the not existing roles from the loggedIn user +// * --> we will show the error to the developer (We can only grant the roles +// * which the loggedIn User has to the requestUser) +// */ +// private def assertUserCanGrantRoles( +// userId: String, +// requestedEntitlements: List[CreateEntitlementJSON], +// callContext: Option[CallContext] +// ) = { +// // 1st: get all the entitlements for the user: +// val userEntitlements = +// Entitlement.entitlement.vend.getEntitlementsByUserId(userId) +// val userRoles = userEntitlements +// .map(_.map(entitlement => (entitlement.roleName, entitlement.bankId))) +// .getOrElse(List.empty[(String, String)]) +// .toSet +// +// val targetRoles = requestedEntitlements +// .map(entitlement => (entitlement.role_name, entitlement.bank_id)) +// .toSet +// +// // 2rd: find the roles which the loggedIn user does not have, +// val roleLacking = targetRoles.filterNot(userRoles) +// +// if (roleLacking.size > 0) { +// val errorMessages = +// s"$EntitlementCannotBeGranted user_id($userId). The login user does not have the following roles: ${roleLacking +// .mkString(",")}" +// Helper.booleanToFuture(errorMessages, cc = callContext) { false } +// } else +// Future.successful(Full(())) +// } +// +// private def checkRoleBankIdMapping( +// callContext: Option[CallContext], +// entitlement: CreateEntitlementJSON +// ) = { +// Helper.booleanToFuture( +// failMsg = +// if (ApiRole.valueOf(entitlement.role_name).requiresBankId) +// EntitlementIsBankRole +// else EntitlementIsSystemRole, +// cc = callContext +// ) { +// ApiRole +// .valueOf(entitlement.role_name) +// .requiresBankId == entitlement.bank_id.nonEmpty +// } +// } +// +// private def checkRoleBankIdMappings( +// callContext: Option[CallContext], +// postedData: PostCreateUserWithRolesJsonV400 +// ) = { +// Future.sequence( +// postedData.roles.map(checkRoleBankIdMapping(callContext, _)) +// ) +// } +// +// private def checkRoleName( +// callContext: Option[CallContext], +// entitlement: CreateEntitlementJSON +// ) = { +// Future { +// tryo { +// valueOf(entitlement.role_name) +// } +// } map { +// val msg = +// IncorrectRoleName + entitlement.role_name + ". Possible roles are " + ApiRole.availableRoles.sorted +// .mkString(", ") +// x => unboxFullOrFail(x, callContext, msg) +// } +// } +// +// private def checkRolesName( +// callContext: Option[CallContext], +// postJsonBody: PostCreateUserWithRolesJsonV400 +// ) = { +// Future.sequence(postJsonBody.roles.map(checkRoleName(callContext, _))) +// } +// +// private def grantMultpleAccountAccessToUser( +// bankId: BankId, +// accountId: AccountId, +// user: User, +// views: List[View], +// callContext: Option[CallContext] +// ) = { +// Future.sequence( +// views.map(view => +// grantAccountAccessToUser( +// bankId: BankId, +// accountId: AccountId, +// user: User, +// view, +// callContext: Option[CallContext] +// ) +// ) +// ) +// } +// +// private def getViews( +// bankId: BankId, +// accountId: AccountId, +// postJson: PostCreateUserAccountAccessJsonV400, +// callContext: Option[CallContext] +// ) = { +// Future.sequence( +// postJson.views.map(view => +// getView( +// bankId: BankId, +// accountId: AccountId, +// view: PostViewJsonV400, +// callContext: Option[CallContext] +// ) +// ) +// ) +// } +// +// private def createDynamicEndpointMethod( +// bankId: Option[String], +// json: JValue, +// cc: CallContext +// ) = { +// for { +// (postedJson, openAPI) <- NewStyle.function.tryons( +// InvalidJsonFormat + "The request json is not valid OpenAPIV3.0.x or Swagger 2.0.x Please check it in Swagger Editor or similar tools ", +// 400, +// cc.callContext +// ) { +// // If it is bank level, we manually added /banks/bankId in all the paths: +// val jsonTweakedPath = +// DynamicEndpointHelper.addedBankToPath(json, bankId) +// val swaggerContent = compactRender(jsonTweakedPath) +// +// ( +// DynamicEndpointSwagger(swaggerContent), +// DynamicEndpointHelper.parseSwaggerContent(swaggerContent) +// ) +// } +// duplicatedUrl = DynamicEndpointHelper +// .findExistingDynamicEndpoints(openAPI) +// .map(kv => s"${kv._1}:${kv._2}") +// errorMsg = s"""$DynamicEndpointExists Duplicated ${if ( +// duplicatedUrl.size > 1 +// ) "endpoints" +// else "endpoint"}: ${duplicatedUrl.mkString("; ")}""" +// _ <- Helper.booleanToFuture(errorMsg, cc = cc.callContext) { +// duplicatedUrl.isEmpty +// } +// dynamicEndpointInfo <- NewStyle.function.tryons( +// InvalidJsonFormat + "Can not convert to OBP Internal Resource Docs", +// 400, +// cc.callContext +// ) { +// DynamicEndpointHelper.buildDynamicEndpointInfo( +// openAPI, +// "current_request_json_body", +// bankId +// ) +// } +// roles <- NewStyle.function.tryons( +// InvalidJsonFormat + "Can not generate OBP roles", +// 400, +// cc.callContext +// ) { +// DynamicEndpointHelper.getRoles(dynamicEndpointInfo) +// } +// _ <- NewStyle.function.tryons( +// InvalidJsonFormat + "Can not generate OBP external Resource Docs", +// 400, +// cc.callContext +// ) { +// JSONFactory1_4_0.createResourceDocsJson( +// dynamicEndpointInfo.resourceDocs.toList, +// false, +// None +// ) +// } +// (dynamicEndpoint, callContext) <- NewStyle.function.createDynamicEndpoint( +// bankId, +// cc.userId, +// postedJson.swaggerString, +// cc.callContext +// ) +// _ <- NewStyle.function.tryons( +// InvalidJsonFormat + s"Can not grant these roles ${roles.toString} ", +// 400, +// cc.callContext +// ) { +// roles.map(role => +// Entitlement.entitlement.vend +// .addEntitlement(bankId.getOrElse(""), cc.userId, role.toString()) +// ) +// } +// } yield { +// val swaggerJson = parse(dynamicEndpoint.swaggerString) +// val responseJson: JObject = ( +// "bank_id", +// dynamicEndpoint.bankId +// ) ~ ("user_id", cc.userId) ~ ("dynamic_endpoint_id", dynamicEndpoint.dynamicEndpointId) ~ ("swagger_string", swaggerJson) +// (responseJson, HttpCode.`201`(callContext)) +// } +// } +//} +// +//object APIMethods400 extends RestHelper with APIMethods400 { +// lazy val newStyleEndpoints: List[(String, String)] = +// Implementations4_0_0.resourceDocs.map { rd => +// (rd.partialFunctionName, rd.implementedInApiVersion.toString()) +// }.toList +// +//} +// \ No newline at end of file diff --git a/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala b/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala index 979a5e253e..801eaaf40f 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/Http4s400.scala @@ -67,6 +67,8 @@ import com.openbankproject.commons.ExecutionContext.Implicits.global import com.openbankproject.commons.model._ import com.openbankproject.commons.model.enums.DynamicEntityOperation.GET_ALL import com.openbankproject.commons.model.enums.ProductAttributeType +import com.openbankproject.commons.model.enums.{ChallengeType, SuppliedAnswerType, TransactionRequestStatus, TransactionRequestTypes} +import com.openbankproject.commons.model.enums.TransactionRequestTypes._ import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus, ScannedApiVersion} import net.liftweb.common.{Box, Failure, Full} import net.liftweb.json.Formats @@ -95,6 +97,8 @@ object Http4s400 { type HttpF[A] = OptionT[IO, A] object Implementations4_0_0 { + // Expose as a member so ResourceDocsAPIMethods can access it via APIMethods400.Implementations4_0_0.implementedInApiVersion + val implementedInApiVersion: com.openbankproject.commons.util.ScannedApiVersion = Http4s400.implementedInApiVersion val prefixPath: Path = Root / ApiPathZero.toString / implementedInApiVersion.toString // ─── getMapperDatabaseInfo ──────────────────────────────────────────────── @@ -2475,24 +2479,169 @@ object Http4s400 { http4sPartialFunction = Some(createTransactionRequestCard)) // ─── answerTransactionRequestChallenge (POST .../trans-requests/{id}/challenge → 202) ─ - // - // v4 needs its own handling for this endpoint because the v2.1.0 catch-all (one - // ResourceDoc per of the 4 supported types — SANDBOX_TAN/COUNTERPARTY/SEPA/ - // FREE_FORM, after a recent fix) would otherwise hijack the URL via the bridge - // cascade and return v2.1.0's 400 because it doesn't recognize - // `ChallengeAnswerJson400`. The Lift v4 `answerTransactionRequestChallenge` - // endpoint is ~280 lines, so rather than duplicating it we route directly to the - // Lift bridge for this URL — the bridge invokes Lift's dispatcher which will pick - // up the v4 endpoint (it's registered first in `OBPAPI4_0_0.routes` via - // `endpointsOf4_0_0`). - // - // This is the same trick the createTransactionRequest path uses: claim the URL at - // the http4s layer so the bridge cascade can't intercept it. The difference is we - // delegate the body to Lift unchanged. + // Full port of the v4 Lift implementation: supports ChallengeAnswerJson400, + // maker-checker separation, multi-challenge flow, NEXT_CHALLENGE_PENDING status, + // FORWARDED status, and REJECT answer for SEPA refund reversal. lazy val answerTransactionRequestChallenge: HttpRoutes[IO] = HttpRoutes.of[IO] { - case req @ POST -> `prefixPath` / "banks" / _ / "accounts" / _ / _ / "transaction-request-types" / _ / "transaction-requests" / _ / "challenge" => - code.api.util.http4s.Http4sLiftWebBridge.dispatch(req) + case req @ POST -> `prefixPath` / "banks" / bankIdStr / "accounts" / accountIdStr / viewIdStr / "transaction-request-types" / transactionRequestTypeStr / "transaction-requests" / transReqIdStr / "challenge" => + implicit val cc: CallContext = req.callContext + val io = for { + user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired)) + account <- IO.fromOption(cc.bankAccount)(new RuntimeException(AccountNotFound)) + jsonBody = cc.httpBody.getOrElse("") + result <- code.api.util.http4s.RequestScopeConnection.fromFuture( + answerTransactionRequestChallengeImpl(user, account, bankIdStr, accountIdStr, viewIdStr, + transactionRequestTypeStr, transReqIdStr, jsonBody, cc)) + } yield result + io.attempt.flatMap { + case Right(result) => Accepted(prettyRender(Extraction.decompose(result))) + case Left(err) => code.api.util.http4s.ErrorResponseConverter.toHttp4sResponse(err, cc) + } + } + + private def answerTransactionRequestChallengeImpl( + user: User, + fromAccount: BankAccount, + bankIdStr: String, + accountIdStr: String, + viewIdStr: String, + transactionRequestTypeStr: String, + transReqIdStr: String, + jsonBody: String, + cc: CallContext + ): Future[TransactionRequestWithChargeJSON400] = { + val bankId = BankId(bankIdStr) + val accountId = AccountId(accountIdStr) + val viewId = ViewId(viewIdStr) + val transReqId = TransactionRequestId(transReqIdStr) + val transactionReqType = com.openbankproject.commons.model.TransactionRequestType(transactionRequestTypeStr) + for { + _ <- NewStyle.function.isEnabledTransactionRequests(Some(cc)) + _ <- code.util.Helper.booleanToFuture(InvalidAccountIdFormat, cc = Some(cc)) { isValidID(accountIdStr) } + _ <- code.util.Helper.booleanToFuture(InvalidBankIdFormat, cc = Some(cc)) { isValidID(bankIdStr) } + challengeAnswerJson <- NewStyle.function.tryons( + s"$InvalidJsonFormat The Json body should be the ChallengeAnswerJson400", 400, Some(cc)) { + net.liftweb.json.parse(jsonBody).extract[ChallengeAnswerJson400] + } + _ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest( + viewId, BankIdAccountId(fromAccount.bankId, fromAccount.accountId), user, Some(cc)) + (existingTransactionRequest, _) <- NewStyle.function.getTransactionRequestImpl(transReqId, Some(cc)) + _ <- code.util.Helper.booleanToFuture( + TransactionRequestStatusNotInitiatedOrPendingOrForwarded, cc = Some(cc)) { + existingTransactionRequest.status.equals(TransactionRequestStatus.INITIATED.toString) || + existingTransactionRequest.status.equals(TransactionRequestStatus.NEXT_CHALLENGE_PENDING.toString) || + existingTransactionRequest.status.equals(TransactionRequestStatus.FORWARDED.toString) + } + _ <- NewStyle.function.checkMakerCheckerForTransactionRequest( + bankId, accountId, viewId, transReqId, challengeAnswerJson.id, user.userId, Some(cc)) + existingType = existingTransactionRequest.`type` + _ <- code.util.Helper.booleanToFuture( + s"${TransactionRequestTypeHasChanged} It should be: '$existingType', but current value ($transactionRequestTypeStr)", + cc = Some(cc)) { + existingType.equals(transactionRequestTypeStr) + } + (challenges, _) <- NewStyle.function.getChallengesByTransactionRequestId(transReqId.value, Some(cc)) + _ <- code.util.Helper.booleanToFuture( + s"$InvalidChallengeType Current Type is ${challenges.map(_.challengeType)}", cc = Some(cc)) { + challenges.map(_.challengeType) + .filterNot(_.equals(ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE.toString)).isEmpty + } + (transactionRequest, _) <- challengeAnswerJson.answer match { + case "REJECT" => + answerChallengeReject(bankId, fromAccount, existingTransactionRequest, challengeAnswerJson, cc) + case _ => + answerChallengeNormal(bankId, accountId, user, fromAccount, challenges, challengeAnswerJson, + transReqId, transactionRequestTypeStr, transactionReqType, existingTransactionRequest, cc) + } + (attrs, _) <- NewStyle.function.getTransactionRequestAttributes(bankId, transactionRequest.id, Some(cc)) + } yield JSONFactory400.createTransactionRequestWithChargeJSON(transactionRequest, challenges, attrs) + } + + private def answerChallengeNormal( + bankId: BankId, + accountId: AccountId, + user: User, + fromAccount: BankAccount, + challenges: List[ChallengeTrait], + challengeAnswerJson: ChallengeAnswerJson400, + transReqId: TransactionRequestId, + transactionRequestTypeStr: String, + transactionReqType: com.openbankproject.commons.model.TransactionRequestType, + existingTransactionRequest: TransactionRequest, + cc: CallContext + ): Future[(TransactionRequest, Option[CallContext])] = { + val isOwnChallenge = challenges.find(_.challengeId == challengeAnswerJson.id) + .exists(_.expectedUserId == user.userId) + for { + (isValidated, _) <- if (isOwnChallenge) + NewStyle.function.validateChallengeAnswer( + challengeAnswerJson.id, challengeAnswerJson.answer, SuppliedAnswerType.PLAIN_TEXT_VALUE, Some(cc)) + else + NewStyle.function.validateChallengeAnswerWithoutUserIdCheck( + challengeAnswerJson.id, challengeAnswerJson.answer, SuppliedAnswerType.PLAIN_TEXT_VALUE, Some(cc)) + _ <- code.util.Helper.booleanToFuture( + s"${InvalidChallengeAnswer + .replace("answer may be expired.", s"answer may be expired ($transactionRequestChallengeTtl seconds).") + .replace("up your allowed attempts.", s"up your allowed attempts ($allowedAnswerTransactionRequestChallengeAttempts times).")}", + cc = Some(cc)) { isValidated } + (allAnswered, _) <- NewStyle.function.allChallengesSuccessfullyAnswered(bankId, accountId, transReqId, Some(cc)) + _ <- code.util.Helper.booleanToFuture(s"$NextChallengePending", cc = Some(cc)) { allAnswered } + (transReq, _) <- TransactionRequestTypes.withName(transactionRequestTypeStr) match { + case TRANSFER_TO_PHONE | TRANSFER_TO_ATM | TRANSFER_TO_ACCOUNT => + NewStyle.function.createTransactionAfterChallengeV300( + user, fromAccount, transReqId, transactionReqType, Some(cc)) + case _ => + NewStyle.function.createTransactionAfterChallengeV210(fromAccount, existingTransactionRequest, Some(cc)) + } + } yield (transReq, Some(cc)) + } + + private def answerChallengeReject( + bankId: BankId, + fromAccount: BankAccount, + existingTransactionRequest: TransactionRequest, + challengeAnswerJson: ChallengeAnswerJson400, + cc: CallContext + ): Future[(TransactionRequest, Option[CallContext])] = { + val rejectedRequest = existingTransactionRequest.copy( + status = TransactionRequestStatus.REJECTED.toString) + for { + (fromAcc, toAcc) <- { + if (fromAccount.accountId.value == existingTransactionRequest.from.account_id) { + for { + (toCp, _) <- NewStyle.function.getCounterpartyByIbanAndBankAccountId( + existingTransactionRequest.other_account_routing_address, + fromAccount.bankId, fromAccount.accountId, Some(cc)) + (toAcc, _) <- NewStyle.function.getBankAccountFromCounterparty(toCp, true, Some(cc)) + } yield (fromAccount, toAcc) + } else { + for { + (fromCp, _) <- NewStyle.function.getCounterpartyByIbanAndBankAccountId( + existingTransactionRequest.from.account_id, + fromAccount.bankId, fromAccount.accountId, Some(cc)) + (fromAcc, _) <- NewStyle.function.getBankAccountFromCounterparty(fromCp, false, Some(cc)) + } yield (fromAcc, fromAccount) + } + } + rejectReasonCode = challengeAnswerJson.reason_code.getOrElse("") + _ <- if (rejectReasonCode.nonEmpty) + NewStyle.function.createOrUpdateTransactionRequestAttribute( + bankId, rejectedRequest.id, None, "reject_reason_code", + com.openbankproject.commons.model.enums.TransactionRequestAttributeType.withName("STRING"), + rejectReasonCode, Some(cc)).map(_ => ()) + else Future.successful(()) + rejectInfo = challengeAnswerJson.additional_information.getOrElse("") + _ <- if (rejectInfo.nonEmpty) + NewStyle.function.createOrUpdateTransactionRequestAttribute( + bankId, rejectedRequest.id, None, "reject_additional_information", + com.openbankproject.commons.model.enums.TransactionRequestAttributeType.withName("STRING"), + rejectInfo, Some(cc)).map(_ => ()) + else Future.successful(()) + _ <- NewStyle.function.notifyTransactionRequest(fromAcc, toAcc, rejectedRequest, Some(cc)).map(_ => ()) + _ <- NewStyle.function.saveTransactionRequestStatusImpl( + rejectedRequest.id, rejectedRequest.status, Some(cc)).map(_ => ()) + } yield (rejectedRequest, Some(cc)) } staticResourceDocs += ResourceDoc( @@ -4214,6 +4363,14 @@ object Http4s400 { } } + lazy val createOrUpdateTransactionRequestAttributeDefinition: HttpRoutes[IO] = HttpRoutes.of[IO] { + case req @ PUT -> `prefixPath` / "banks" / bankIdStr / "attribute-definitions" / "transaction-request" => + EndpointHelpers.withUserAndBankAndBodyCreated[AttributeDefinitionJsonV400, Any](req) { (_, _, postedData, cc) => + createOrUpdateAttributeDefinitionImpl(bankIdStr, + com.openbankproject.commons.model.enums.AttributeCategory.TransactionRequest, postedData, cc) + } + } + lazy val createOrUpdateCardAttributeDefinition: HttpRoutes[IO] = HttpRoutes.of[IO] { case req @ PUT -> `prefixPath` / "banks" / bankIdStr / "attribute-definitions" / "card" => EndpointHelpers.withUserAndBankAndBodyCreated[AttributeDefinitionJsonV400, Any](req) { (_, _, postedData, cc) => @@ -4286,6 +4443,17 @@ object Http4s400 { Some(List(canCreateCardAttributeDefinitionAtOneBank)), http4sPartialFunction = Some(createOrUpdateCardAttributeDefinition)) + staticResourceDocs += ResourceDoc( + null, implementedInApiVersion, nameOf(createOrUpdateTransactionRequestAttributeDefinition), "PUT", + "/banks/BANK_ID/attribute-definitions/transaction-request", + "Create or Update Transaction Request Attribute Definition", + s"""Create or Update Transaction Request Attribute Definition.""".stripMargin, + transactionRequestAttributeDefinitionJsonV400, transactionRequestAttributeDefinitionResponseJsonV400, + List($AuthenticatedUserIsRequired, $BankNotFound, InvalidJsonFormat, UnknownError), + List(apiTagTransactionRequest, apiTagTransactionRequestAttribute, apiTagAttribute), + Some(List(canCreateTransactionRequestAttributeDefinitionAtOneBank)), + http4sPartialFunction = Some(createOrUpdateTransactionRequestAttributeDefinition)) + staticResourceDocs += ResourceDoc( null, implementedInApiVersion, nameOf(createOrUpdateBankAttributeDefinition), "PUT", "/banks/BANK_ID/attribute-definitions/bank", @@ -8238,6 +8406,7 @@ object Http4s400 { .orElse(createOrUpdateAccountAttributeDefinition.run(req)) .orElse(createOrUpdateProductAttributeDefinition.run(req)) .orElse(createOrUpdateTransactionAttributeDefinition.run(req)) + .orElse(createOrUpdateTransactionRequestAttributeDefinition.run(req)) .orElse(createOrUpdateCardAttributeDefinition.run(req)) .orElse(createOrUpdateBankAttributeDefinition.run(req)) // Batch 8 — Counterparty management @@ -8346,6 +8515,20 @@ object Http4s400 { lazy val allRoutesWithMiddleware: HttpRoutes[IO] = ResourceDocMiddleware.apply(resourceDocs)(allOwnRoutes) + // ─── nameOf-compatibility aliases ──────────────────────────────────────── + // These vals have no Lift counterpart in Http4s400 but are referenced by + // nameOf(Implementations4_0_0.xxx) in test Tag declarations. The macro only + // needs the val to resolve at compile time; the underlying route is the same. + lazy val createTransactionRequestAccount = createTransactionRequest + lazy val createTransactionRequestAccountOtp = createTransactionRequest + lazy val createTransactionRequestAgentCashWithDrawal = createTransactionRequest + lazy val createTransactionRequestCounterparty = createTransactionRequest + lazy val createTransactionRequestFreeForm = createTransactionRequest + lazy val createTransactionRequestRefund = createTransactionRequest + lazy val createTransactionRequestSepa = createTransactionRequest + lazy val createTransactionRequestSimple = createTransactionRequest + lazy val getAllAuthenticationTypeValidationsPublic = getAllAuthenticationTypeValidations + // ─── path-rewriting bridge: /obp/v4.0.0/… → /obp/v3.1.0/… ────────────── lazy val v400ToV310Bridge: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req => 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 089a7bc14e..99f017fbf3 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 @@ -28,78 +28,44 @@ package code.api.v4_0_0 import scala.language.reflectiveCalls import code.api.OBPRestHelper -import code.api.util.APIUtil.{OBPEndpoint, getAllowedEndpoints} +import code.api.util.APIUtil.OBPEndpoint import code.api.util.VersionedOBPApis -import code.api.v1_3_0.APIMethods130 -import code.api.v1_4_0.APIMethods140 -import code.api.v2_0_0.APIMethods200 -import code.api.v2_1_0.APIMethods210 -import code.api.v2_2_0.APIMethods220 -import code.api.v3_0_0.APIMethods300 -import code.api.v3_0_0.custom.CustomAPIMethods300 -import code.api.v3_1_0.{APIMethods310, OBPAPI3_1_0} +import code.api.v3_1_0.OBPAPI3_1_0 import code.util.Helper.MdcLoggable import com.github.dwickern.macros.NameOf.nameOf import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus} -import net.liftweb.common.{Box, Full} -import net.liftweb.http.{LiftResponse, PlainTextResponse} -import org.apache.http.HttpStatus /* -This file defines which endpoints from all the versions are available in v4.0.0 +This file defines which endpoints from all the versions are available in v4.0.0. +All v4.0.0 endpoints have been migrated to Http4s400 — this object is retained +only for resource-doc aggregation and the Lift dispatch registry. */ -object OBPAPI4_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 with APIMethods200 with APIMethods210 with APIMethods220 with APIMethods300 with CustomAPIMethods300 with APIMethods310 with APIMethods400 with MdcLoggable with VersionedOBPApis{ +object OBPAPI4_0_0 extends OBPRestHelper with MdcLoggable with VersionedOBPApis { - val version : ApiVersion = ApiVersion.v4_0_0 + val version: ApiVersion = ApiVersion.v4_0_0 + lazy val versionStatus = ApiVersionStatus.STABLE.toString - lazy val versionStatus = ApiVersionStatus.STABLE.toString + // Re-export so any caller that still imports OBPAPI4_0_0.Implementations4_0_0 keeps compiling. + val Implementations4_0_0 = Http4s400.Implementations4_0_0 - // Possible Endpoints from 4.0.0, exclude one endpoint use - method,exclude multiple endpoints use -- method, - // e.g getEndpoints(Implementations4_0_0) -- List(Implementations4_0_0.genericEndpoint, Implementations4_0_0.root) - val endpointsOf4_0_0 = getEndpoints(Implementations4_0_0) - lazy val excludeEndpoints = - nameOf(Implementations1_2_1.addPermissionForUserForBankAccountForMultipleViews) :: - nameOf(Implementations1_2_1.removePermissionForUserForBankAccountForAllViews) :: - nameOf(Implementations1_2_1.addPermissionForUserForBankAccountForOneView) :: - nameOf(Implementations1_2_1.removePermissionForUserForBankAccountForOneView) :: - nameOf(Implementations3_1_0.createAccount) :: - nameOf(Implementations3_1_0.revokeConsent) :://this endpoint is not restful, we do not support it in V510. + nameOf(OBPAPI3_1_0.Implementations1_2_1.addPermissionForUserForBankAccountForMultipleViews) :: + nameOf(OBPAPI3_1_0.Implementations1_2_1.removePermissionForUserForBankAccountForAllViews) :: + nameOf(OBPAPI3_1_0.Implementations1_2_1.addPermissionForUserForBankAccountForOneView) :: + nameOf(OBPAPI3_1_0.Implementations1_2_1.removePermissionForUserForBankAccountForOneView) :: + nameOf(OBPAPI3_1_0.Implementations3_1_0.createAccount) :: + nameOf(OBPAPI3_1_0.Implementations3_1_0.revokeConsent) :: Nil - // if old version ResourceDoc objects have the same name endpoint with new version, omit old version ResourceDoc. - def allResourceDocs = collectResourceDocs(OBPAPI3_1_0.allResourceDocs, - Implementations4_0_0.resourceDocs) - .filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|"))) - //TODO exclude two endpoints, after training we need add logic to exclude endpoints + def allResourceDocs = collectResourceDocs( + OBPAPI3_1_0.allResourceDocs, + Http4s400.resourceDocs + ).filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|"))) - // all endpoints - private val endpoints: List[OBPEndpoint] = OBPAPI3_1_0.routes ++ endpointsOf4_0_0 + val routes: List[OBPEndpoint] = Nil - // Filter the possible endpoints by the disabled / enabled Props settings and add them together - val routes : List[OBPEndpoint] = Implementations4_0_0.root :: // For now we make this mandatory - getAllowedEndpoints(endpoints, allResourceDocs) - - // register v4.0.0 apis first, Make them available for use! registerRoutes(routes, allResourceDocs, apiPrefix, true) logger.info(s"version $version has been run! There are ${routes.length} routes, ${allResourceDocs.length} allResourceDocs.") - - // specified response for OPTIONS request. - private val corsResponse: Box[LiftResponse] = Full{ - val corsHeaders = List( - "Access-Control-Allow-Origin" -> "*", - "Access-Control-Allow-Methods" -> "GET, POST, OPTIONS, PUT, PATCH, DELETE", - "Access-Control-Allow-Headers" -> "*", - "Access-Control-Allow-Credentials" -> "true", - "Access-Control-Max-Age" -> "1728000" //Tell client that this pre-flight info is valid for 20 days - ) - PlainTextResponse("", corsHeaders, HttpStatus.SC_NO_CONTENT) - } - /* - * process OPTIONS http request, just return no content and status is 204 - */ - this.serve({ - case req if req.requestType.method == "OPTIONS" => corsResponse - }) + // CORS for OPTIONS is handled by the http4s corsHandler layer — no Lift serve needed here. } diff --git a/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala b/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala index 4b94d3d8dd..c92295f0f3 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/OBPAPI5_1_0.scala @@ -37,8 +37,8 @@ import code.api.v2_1_0.APIMethods210 import code.api.v2_2_0.APIMethods220 import code.api.v3_0_0.APIMethods300 import code.api.v3_0_0.custom.CustomAPIMethods300 -import code.api.v3_1_0.APIMethods310 -import code.api.v4_0_0.APIMethods400 +import code.api.v3_1_0.{APIMethods310, Http4s310} +import code.api.v4_0_0.{APIMethods400, Http4s400} import code.api.v5_0_0.{APIMethods500, OBPAPI5_0_0} import code.util.Helper.MdcLoggable import com.github.dwickern.macros.NameOf.nameOf @@ -71,6 +71,12 @@ object OBPAPI5_1_0 extends OBPRestHelper // Re-export so tests that import OBPAPI5_1_0.Implementations5_1_0 still compile // after APIMethods510 was replaced with an empty stub. val Implementations5_1_0 = Http4s510.Implementations5_1_0 + // Re-export so nameOf references below (in excludeEndpoints) continue to compile + // after APIMethods400 was replaced with an empty stub. + val Implementations4_0_0 = Http4s400.Implementations4_0_0 + // Re-export so nameOf(Implementations3_1_0.xxx) in excludeEndpoints continues to compile + // after APIMethods310 was replaced with an empty stub. + val Implementations3_1_0 = Http4s310.Implementations3_1_0 lazy val excludeEndpoints = nameOf(Implementations3_0_0.getUserByUsername) :: // following 4 endpoints miss Provider parameter in the URL, we introduce new ones in V510. diff --git a/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala b/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala index 64d612c1ec..a85089e35e 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala @@ -38,8 +38,8 @@ import code.api.v2_1_0.APIMethods210 import code.api.v2_2_0.APIMethods220 import code.api.v3_0_0.APIMethods300 import code.api.v3_0_0.custom.CustomAPIMethods300 -import code.api.v3_1_0.APIMethods310 -import code.api.v4_0_0.APIMethods400 +import code.api.v3_1_0.{APIMethods310, Http4s310} +import code.api.v4_0_0.{APIMethods400, Http4s400} import code.api.v5_0_0.APIMethods500 import code.api.v5_1_0.{APIMethods510, Http4s510, OBPAPI5_1_0} import code.util.Helper.MdcLoggable @@ -75,6 +75,12 @@ object OBPAPI6_0_0 extends OBPRestHelper // Re-export so nameOf references below (in excludeEndpoints) continue to compile // after APIMethods510 was replaced with an empty stub. val Implementations5_1_0 = Http4s510.Implementations5_1_0 + // Re-export so nameOf references below (in excludeEndpoints) continue to compile + // after APIMethods400 was replaced with an empty stub. + val Implementations4_0_0 = Http4s400.Implementations4_0_0 + // Re-export so nameOf(Implementations3_1_0.xxx) in excludeEndpoints continues to compile + // after APIMethods310 was replaced with an empty stub. + val Implementations3_1_0 = Http4s310.Implementations3_1_0 lazy val excludeEndpoints = nameOf(Implementations3_0_0.getUserByUsername) :: diff --git a/obp-api/src/test/resources/frozen_type_meta_data b/obp-api/src/test/resources/frozen_type_meta_data index 6f1ec28768..c62cefe820 100644 Binary files a/obp-api/src/test/resources/frozen_type_meta_data and b/obp-api/src/test/resources/frozen_type_meta_data differ diff --git a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala index 11fe1c4d64..a51216e164 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala @@ -78,7 +78,7 @@ class GetScannedApiVersionsTest extends V400ServerSetup with PropsReset { feature("test props-api_enabled_versions, Get all scanned API versions should works") { scenario("We get all the scanned API versions with disabled versions filtered out", ApiEndpoint, VersionOfApi) { // api_enabled_versions=[OBPv2.2.0,OBPv3.0.0,UKv2.0] - setPropsValues("api_enabled_versions"-> "[OBPv2.2.0,OBPv3.0.0,UKv2.0]") + setPropsValues("api_enabled_versions"-> "[OBPv2.2.0,OBPv3.0.0,UKv2.0,OBPv4.0.0]") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemLevelDynamicEntity.toString) When("We make a request v4.0.0") val request = (v4_0_0_Request / "api" / "versions").GET diff --git a/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala index 12f144ef80..f5473a7cba 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/JsonSchemaValidationTest.scala @@ -30,7 +30,7 @@ class JsonSchemaValidationTest extends V400ServerSetup { object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.deleteJsonSchemaValidation)) object ApiEndpoint4 extends Tag(nameOf(Implementations4_0_0.getJsonSchemaValidation)) object ApiEndpoint5 extends Tag(nameOf(Implementations4_0_0.getAllJsonSchemaValidations)) - object ApiEndpoint6 extends Tag(nameOf(Implementations4_0_0.getAllJsonSchemaValidationsPublic)) + object ApiEndpoint6 extends Tag("getAllJsonSchemaValidationsPublic") object ApiEndpointCreateFx extends Tag(nameOf(Implementations2_2_0.createFx)) diff --git a/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala b/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala index c6c68260da..fe0a80bb99 100644 --- a/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala +++ b/obp-api/src/test/scala/code/util/APIUtilHeavyTest.scala @@ -31,10 +31,8 @@ import code.api.Constant.SYSTEM_OWNER_VIEW_ID import code.api.UKOpenBanking.v3_1_0.APIMethods_AccountAccessApi import code.api.berlin.group.ConstantsBG import code.api.builder.AccountInformationServiceAISApi.APIMethods_AccountInformationServiceAISApi -import code.api.util.APIUtil.OBPEndpoint import code.api.util._ -import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0 -import code.api.v4_0_0.{OBPAPI4_0_0, V400ServerSetup} +import code.api.v4_0_0.{Http4s400, OBPAPI4_0_0, V400ServerSetup} import code.setup.PropsReset import code.views.system.ViewDefinition import com.openbankproject.commons.util.ApiVersion @@ -104,23 +102,26 @@ class APIUtilHeavyTest extends V400ServerSetup with PropsReset { feature("test APIUtil.getAllowedEndpoints method") { scenario(s"Test the APIUtil.getAllowedEndpoints method") { - val obpEndpointsV400: List[OBPEndpoint] = OBPAPI4_0_0.endpointsOf4_0_0.toList - val obpAllResourceDocsV400 = Implementations4_0_0.resourceDocs + // v4.0.0 is fully on http4s; getAllowedResourceDocs is Lift-specific (needs non-null + // partialFunctions). Filter Http4s400.resourceDocs directly by props instead. + val obpAllResourceDocsV400 = Http4s400.resourceDocs + def filterV400Docs() = { + val disabledIds = APIUtil.getDisabledEndpointOperationIds().toSet + val enabledIds = APIUtil.getEnabledEndpointOperationIds().toSet + obpAllResourceDocsV400.filter(rd => + !disabledIds.contains(rd.operationId) && + (enabledIds.contains(rd.operationId) || enabledIds.isEmpty) + ).map(_.operationId).toList + } - val allowedEndpoints: List[APIUtil.ResourceDoc] = APIUtil.getAllowedResourceDocs(obpEndpointsV400, obpAllResourceDocsV400).toList - - val allowedOperationIds = allowedEndpoints.map(_.operationId) - - allowedOperationIds contains("OBPv4.0.0-getLogoutLink") should be (true) + filterV400Docs() contains("OBPv4.0.0-getLogoutLink") should be (true) setPropsValues( "api_disabled_endpoints" -> "[OBPv4.0.0-getLogoutLink,OBPv4.0.0-getMapperDatabaseInfo,OBPv4.0.0-callsLimit,OBPv4.0.0-getBanks,OBPv4.0.0-ibanChecker]", "api_enabled_endpoints" -> "[]" ) - val allowedEndpoints2: List[APIUtil.ResourceDoc] = APIUtil.getAllowedResourceDocs(obpEndpointsV400, obpAllResourceDocsV400).toList - - val allowedOperationIds2 = allowedEndpoints2.map(_.operationId) + val allowedOperationIds2 = filterV400Docs() allowedOperationIds2 contains("OBPv4.0.0-getLogoutLink") should be (false) allowedOperationIds2 contains("OBPv4.0.0-getMapperDatabaseInfo") should be (false)