Merge pull request #2549 from hongwei1/develop

feature/consents pages
This commit is contained in:
Simon Redfern 2025-05-27 17:05:26 +02:00 committed by GitHub
commit 401e1b64ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 368 additions and 54 deletions

View File

@ -564,6 +564,7 @@ class Boot extends MdcLoggable {
Menu.i("Plain") / "plain",
Menu.i("Static") / "static",
Menu.i("SDKs") / "sdks",
Menu.i("Consents") / "consents",
Menu.i("Debug") / "debug",
Menu.i("debug-basic") / "debug" / "debug-basic",
Menu.i("debug-default-header") / "debug" / "debug-default-header",

View File

@ -12,7 +12,6 @@ import code.api.util.{ApiRole, ApiTrigger, ExampleValue}
import code.api.v2_2_0.JSONFactory220.{AdapterImplementationJson, MessageDocJson, MessageDocsJson}
import code.api.v3_0_0.JSONFactory300.createBranchJsonV300
import code.api.v3_0_0._
import code.api.v3_0_0.custom.JSONFactoryCustom300
import code.api.v3_1_0._
import code.api.v4_0_0._
import code.api.v5_0_0._
@ -22,7 +21,6 @@ import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody}
import code.consent.ConsentStatus
import code.dynamicMessageDoc.JsonDynamicMessageDoc
import code.dynamicResourceDoc.JsonDynamicResourceDoc
import code.sandbox.SandboxData
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model
import com.openbankproject.commons.model.PinResetReason.{FORGOT, GOOD_SECURITY_PRACTICE}
@ -4248,7 +4246,7 @@ object SwaggerDefinitionsJSON {
)
lazy val allConsentJsonV510 = AllConsentJsonV510(
consent_reference_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
consent_reference_id = consentReferenceIdExample.value,
consumer_id = consumerIdExample.value,
created_by_user_id = userIdExample.value,
last_action_date = dateExample.value,
@ -4259,6 +4257,7 @@ object SwaggerDefinitionsJSON {
jwt_payload = Some(consentJWT)
)
lazy val consentInfoJsonV510 = ConsentInfoJsonV510(
consent_reference_id = consentReferenceIdExample.value,
consent_id = consentIdExample.value,
consumer_id = consumerIdExample.value,
created_by_user_id = userIdExample.value,

View File

@ -4,15 +4,14 @@ import code.api.APIFailureNewStyle
import code.api.Constant.{SYSTEM_READ_ACCOUNTS_BERLIN_GROUP_VIEW_ID, SYSTEM_READ_BALANCES_BERLIN_GROUP_VIEW_ID, SYSTEM_READ_TRANSACTIONS_BERLIN_GROUP_VIEW_ID}
import code.api.berlin.group.ConstantsBG
import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{PostConsentResponseJson, _}
import code.api.berlin.group.v1_3.model.{HrefType, LinksAll, ScaStatusResponse}
import code.api.berlin.group.v1_3.{BgSpecValidation, JSONFactory_BERLIN_GROUP_1_3, JvalueCaseClass, OBP_BERLIN_GROUP_1_3}
import code.api.berlin.group.v1_3.model._
import code.api.berlin.group.v1_3.{BgSpecValidation, JSONFactory_BERLIN_GROUP_1_3, JvalueCaseClass}
import code.api.util.APIUtil.{passesPsd2Aisp, _}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.api.util.NewStyle.HttpCode
import code.api.util.newstyle.BalanceNewStyle
import code.api.util._
import code.api.util.newstyle.BalanceNewStyle
import code.bankconnectors.Connector
import code.consent.{ConsentStatus, Consents}
import code.context.{ConsentAuthContextProvider, UserAuthContextProvider}
@ -362,10 +361,10 @@ of the PSU at this ASPSP.
attribute.value.equalsIgnoreCase("card")
).isEmpty)
(balances, callContext) <- JSONFactory_BERLIN_GROUP_1_3.flattenOBPReturnType(bankAccountsFiltered.map(bankAccont => code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountBalances(
bankAccont.accountId,
(balances, callContext) <- code.api.util.newstyle.BankAccountBalanceNewStyle.getBankAccountsBalances(
bankAccountsFiltered.map(_.accountId),
callContext
)))
)
} yield {
(JSONFactory_BERLIN_GROUP_1_3.createAccountListJson(

View File

@ -9,8 +9,9 @@ import code.api.util.{APIUtil, ConsentJWT, CustomJsonFormats, JwtUtil}
import code.consent.ConsentTrait
import code.model.ModeratedTransaction
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.model.enums.AccountRoutingScheme
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model._
import com.openbankproject.commons.model.enums.AccountRoutingScheme
import net.liftweb.common.Box.tryo
import net.liftweb.common.{Box, Full}
import net.liftweb.json.{JValue, parse}
@ -18,7 +19,6 @@ import net.liftweb.json.{JValue, parse}
import java.text.SimpleDateFormat
import java.util.Date
import scala.concurrent.Future
import com.openbankproject.commons.ExecutionContext.Implicits.global
case class JvalueCaseClass(jvalueToCaseclass: JValue)
object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
@ -346,13 +346,15 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
None
}
val cashAccountType = x.attributes.getOrElse(Nil).filter(_.name== "cashAccountType").map(_.value).headOption.getOrElse("")
CoreAccountJsonV13(
resourceId = x.accountId.value,
iban = iBan,
bban = None,
currency = x.currency,
name = x.name,
cashAccountType = x.accountType,
cashAccountType = cashAccountType,
product = x.accountType,
balances = if(canReadBalances) accountBalances else None,
_links = CoreAccountLinksJsonV13(

View File

@ -4746,7 +4746,13 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val user = AuthUser.getCurrentUser
val result = tryo {
endpoint(newRequest)(CallContext(user = user))
val headers: List[HTTPParam] = addlParams.get(RequestHeader.`Consent-Id`)
.map(consentId => List(HTTPParam(RequestHeader.`Consent-Id`, List(consentId))))
.getOrElse(Nil)
endpoint(newRequest)(CallContext(
user = user,
requestHeaders = headers))
}
val func: ((=> LiftResponse) => Unit) => Unit = result match {

View File

@ -2,18 +2,18 @@ package code.api.util
import code.api.Constant
import code.api.util.APIUtil.{DateWithMs, DateWithMsExampleString, formatDate, oneYearAgo, oneYearAgoDate, parseDate}
import code.api.util.APIUtil.{DateWithMs, DateWithMsExampleString, formatDate, oneYearAgoDate, parseDate}
import code.api.util.ErrorMessages.{InvalidJsonFormat, UnknownError, UserHasMissingRoles, UserNotLoggedIn}
import net.liftweb.json.JsonDSL._
import code.api.util.Glossary.{glossaryItems, makeGlossaryItem}
import code.apicollection.ApiCollection
import code.dynamicEntity.{DynamicEntityDefinition, DynamicEntityFooBar, DynamicEntityFullBarFields, DynamicEntityIntTypeExample, DynamicEntityStringTypeExample}
import code.dynamicEntity._
import com.openbankproject.commons.model.CardAction
import com.openbankproject.commons.model.enums.{CustomerAttributeType, DynamicEntityFieldType, UserInvitationPurpose}
import com.openbankproject.commons.util.ReflectUtils
import net.liftweb.json
import net.liftweb.json.JObject
import net.liftweb.json.JsonAST.JField
import net.liftweb.json.JsonDSL._
case class ConnectorField(value: String, description: String) {
@ -1586,7 +1586,10 @@ object ExampleValue {
lazy val directDebitIdExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("direct_debit_id", directDebitIdExample)
lazy val consentIdExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
lazy val consentReferenceIdExample = ConnectorField("123456" ,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("consent_id", consentReferenceIdExample)
lazy val consentIdExample = ConnectorField("9d429899-24f5-42c8-8565-943ffa6a7947",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("consent_id", consentIdExample)
lazy val basketIdExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)

View File

@ -1,13 +1,11 @@
package code.api.util.newstyle
import code.api.util.APIUtil.{OBPReturnType, unboxFullOrFail}
import code.bankconnectors.Connector
import code.api.util.{APIUtil, CallContext}
import code.api.util.CallContext
import code.api.util.ErrorMessages.BankAccountBalanceNotFoundById
import code.api.util.{APIUtil, CallContext}
import code.bankconnectors.Connector
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.{AccountId, BankAccountBalanceTrait, BankId}
import com.openbankproject.commons.model.BalanceId
import com.openbankproject.commons.model.{AccountId, BalanceId, BankAccountBalanceTrait, BankId}
object BankAccountBalanceNewStyle {
@ -23,6 +21,18 @@ object BankAccountBalanceNewStyle {
i => (APIUtil.connectorEmptyResponse(i._1, callContext), i._2)
}
}
def getBankAccountsBalances(
accountIds: List[AccountId],
callContext: Option[CallContext]
): OBPReturnType[List[BankAccountBalanceTrait]] = {
Connector.connector.vend.getBankAccountsBalancesByAccountIds(
accountIds: List[AccountId],
callContext: Option[CallContext]
) map {
i => (APIUtil.connectorEmptyResponse(i._1, callContext), i._2)
}
}
def getBankAccountBalanceById(
balanceId: BalanceId,

View File

@ -147,7 +147,8 @@ case class ConsentJsonV510(consent_id: String,
consumer_id:String)
case class ConsentInfoJsonV510(consent_id: String,
case class ConsentInfoJsonV510(consent_reference_id: String,
consent_id: String,
consumer_id: String,
created_by_user_id: String,
status: String,
@ -916,6 +917,7 @@ object JSONFactory510 extends CustomJsonFormats {
consents.map { c =>
val jwtPayload: Box[ConsentJWT] = JwtUtil.getSignedPayloadAsJson(c.jsonWebToken).map(parse(_).extract[ConsentJWT])
ConsentInfoJsonV510(
consent_reference_id = c.consentReferenceId,
consent_id = c.consentId,
consumer_id = c.consumerId,
created_by_user_id = c.userId,

View File

@ -3,12 +3,11 @@ package code.bankaccountbalance
import code.model.dataAccess.MappedBankAccount
import code.util.Helper
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.{BankId, AccountId}
import com.openbankproject.commons.model.{AccountId, BalanceId, BankId}
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.mapper._
import net.liftweb.util.Helpers.tryo
import net.liftweb.util.SimpleInjector
import com.openbankproject.commons.model.BalanceId
import scala.concurrent.Future
@ -31,6 +30,8 @@ object BankAccountBalanceX extends SimpleInjector {
trait BankAccountBalanceProviderTrait {
def getBankAccountBalances(accountId: AccountId): Future[Box[List[BankAccountBalance]]]
def getBankAccountsBalances(accountIds: List[AccountId]): Future[Box[List[BankAccountBalance]]]
def getBankAccountBalanceById(balanceId: BalanceId): Future[Box[BankAccountBalance]]
@ -53,6 +54,13 @@ object MappedBankAccountBalanceProvider extends BankAccountBalanceProviderTrait
By(BankAccountBalance.AccountId_,accountId.value)
)}
}
override def getBankAccountsBalances(accountIds: List[AccountId]): Future[Box[List[BankAccountBalance]]] = Future {
tryo {
BankAccountBalance.findAll(
ByList(BankAccountBalance.AccountId_, accountIds.map(_.value))
)
}
}
override def getBankAccountBalanceById(balanceId: BalanceId): Future[Box[BankAccountBalance]] = Future {
// Find a balance by its ID

View File

@ -12,20 +12,16 @@ import code.bankconnectors.akka.AkkaConnector_vDec2018
import code.bankconnectors.rabbitmq.RabbitMQConnector_vOct2024
import code.bankconnectors.rest.RestConnector_vMar2019
import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019
import com.openbankproject.commons.model.CounterpartyLimitTrait
import com.openbankproject.commons.model.CustomerAccountLinkTrait
import com.openbankproject.commons.model.EndpointTagT
import code.model.dataAccess.BankAccountRouting
import com.openbankproject.commons.model.StandingOrderTrait
import code.users.UserAttribute
import code.util.Helper._
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.{CustomerAndAttribute, GetProductsParam, InBoundTrait, ProductCollectionItemsTree}
import com.openbankproject.commons.model.{TransactionRequestStatus, _}
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA
import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus
import com.openbankproject.commons.model.enums._
import com.openbankproject.commons.model.{TransactionRequestStatus, _}
import com.openbankproject.commons.util.{JsonUtils, ReflectUtils}
import net.liftweb.common._
import net.liftweb.json
@ -1898,6 +1894,11 @@ trait Connector extends MdcLoggable {
accountId: AccountId,
callContext: Option[CallContext]
): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = Future{(Failure(setUnimplementedError(nameOf(getBankAccountBalancesByAccountId(_, _)))), callContext)}
def getBankAccountsBalancesByAccountIds(
accountIds: List[AccountId],
callContext: Option[CallContext]
): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = Future{(Failure(setUnimplementedError(nameOf(getBankAccountsBalancesByAccountIds(_, _)))), callContext)}
def getBankAccountBalanceById(
balanceId: BalanceId,

View File

@ -4,7 +4,7 @@ import _root_.akka.http.scaladsl.model.HttpMethod
import code.DynamicData.DynamicDataProvider
import code.accountapplication.AccountApplicationX
import code.accountattribute.AccountAttributeX
import code.accountholders.{AccountHolders, MapperAccountHolders}
import code.accountholders.AccountHolders
import code.api.Constant
import code.api.Constant._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
@ -18,6 +18,7 @@ import code.api.v2_1_0._
import code.api.v4_0_0.{AgentCashWithdrawalJson, PostSimpleCounterpartyJson400, TransactionRequestBodyAgentJsonV400, TransactionRequestBodySimpleJsonV400}
import code.atmattribute.{AtmAttribute, AtmAttributeX}
import code.atms.{Atms, MappedAtm}
import code.bankaccountbalance.BankAccountBalanceX
import code.bankattribute.{BankAttribute, BankAttributeX}
import code.branches.MappedBranch
import code.cardattribute.CardAttributeX
@ -27,13 +28,10 @@ import code.counterpartylimit.CounterpartyLimitProvider
import code.customer._
import code.customer.agent.AgentX
import code.customeraccountlinks.CustomerAccountLinkX
import com.openbankproject.commons.model.CustomerAccountLinkTrait
import code.customeraddress.CustomerAddressX
import code.customerattribute.CustomerAttributeX
import code.directdebit.DirectDebits
import code.endpointTag.EndpointTag
import code.bankaccountbalance.BankAccountBalanceX
import com.openbankproject.commons.model.EndpointTagT
import code.fx.{MappedFXRate, fx}
import code.kycchecks.KycChecks
import code.kycdocuments.KycDocuments
@ -52,7 +50,6 @@ import code.productfee.ProductFeeX
import code.products.MappedProduct
import code.regulatedentities.MappedRegulatedEntityProvider
import code.standingorders.StandingOrders
import com.openbankproject.commons.model.StandingOrderTrait
import code.taxresidence.TaxResidenceX
import code.transaction.MappedTransaction
import code.transactionChallenge.Challenges
@ -65,14 +62,13 @@ import code.util.Helper._
import code.views.Views
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.{CustomerAndAttribute, GetProductsParam, ProductCollectionItemsTree}
import com.openbankproject.commons.model._
import com.openbankproject.commons.model.enums.ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE
import com.openbankproject.commons.model.enums.DynamicEntityOperation._
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA
import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus
import com.openbankproject.commons.model.enums.TransactionRequestTypes._
import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
import com.openbankproject.commons.model.CustomerAccountLinkTrait
import com.openbankproject.commons.model._
import com.tesobe.CacheKeyFromArguments
import com.tesobe.model.UpdateBankAccount
import com.twilio.Twilio
@ -95,7 +91,7 @@ import scala.collection.immutable.{List, Nil}
import scala.concurrent._
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.math.{BigDecimal, BigInt}
import scala.math.BigDecimal
import scala.util.{Random, Try}
object LocalMappedConnector extends Connector with MdcLoggable {
@ -129,7 +125,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
override def validateAndCheckIbanNumber(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[IbanChecker]] = Future {
import org.iban4j.{IbanFormat, IbanFormatException, IbanUtil, InvalidCheckDigitException, UnsupportedCountryException}
import org.iban4j._
if(getPropsAsBoolValue("validate_iban", false)) {
// Validate Iban
@ -5374,6 +5370,15 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
}
override def getBankAccountsBalancesByAccountIds(
accountIds: List[AccountId],
callContext: Option[CallContext]
): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = {
BankAccountBalanceX.bankAccountBalanceProvider.vend.getBankAccountsBalances(accountIds).map {
(_, callContext)
}
}
override def getBankAccountBalanceById(
balanceId: BalanceId,
callContext: Option[CallContext]

View File

@ -438,6 +438,7 @@ object ConnectorBuilderUtil {
"getRegulatedEntities",
"getRegulatedEntityByEntityId",
"getBankAccountBalancesByAccountId",
"getBankAccountsBalancesByAccountIds",
"getBankAccountBalanceById",
"createOrUpdateBankAccountBalance",
"deleteBankAccountBalance",

View File

@ -3,6 +3,8 @@ package code.bankconnectors.rabbitmq.Adapter
import bootstrap.liftweb.ToSchemify
import code.api.util.APIUtil
import code.bankconnectors.rabbitmq.RabbitMQUtils
import code.bankconnectors.rabbitmq.RabbitMQUtils._
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto._
import com.openbankproject.commons.model._
@ -13,11 +15,8 @@ import net.liftweb.json
import net.liftweb.json.Serialization.write
import net.liftweb.mapper.Schemifier
import scala.concurrent.Future
import com.openbankproject.commons.ExecutionContext.Implicits.global
import code.bankconnectors.rabbitmq.RabbitMQUtils._
import java.util.Date
import code.util.Helper.MdcLoggable
import scala.concurrent.Future
class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
@ -77,7 +76,7 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
))
}
//---------------- dynamic start -------------------please don't modify this line
// ---------- created on 2025-04-07T14:53:47Z
// ---------- created on 2025-05-27T08:15:58Z
} else if (obpMessageId.contains("get_adapter_info")) {
val outBound = json.parse(message).extract[OutBoundGetAdapterInfo]
@ -3151,6 +3150,111 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
data = null
))
}
} else if (obpMessageId.contains("get_bank_account_balances_by_account_id")) {
val outBound = json.parse(message).extract[OutBoundGetBankAccountBalancesByAccountId]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.getBankAccountBalancesByAccountId(outBound.accountId,None).map(_._1.head)
obpMappedResponse.map(response => InBoundGetBankAccountBalancesByAccountId(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundGetBankAccountBalancesByAccountId(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("get_bank_accounts_balances_by_account_ids")) {
val outBound = json.parse(message).extract[OutBoundGetBankAccountsBalancesByAccountIds]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.getBankAccountsBalancesByAccountIds(outBound.accountIds,None).map(_._1.head)
obpMappedResponse.map(response => InBoundGetBankAccountsBalancesByAccountIds(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundGetBankAccountsBalancesByAccountIds(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("get_bank_account_balance_by_id")) {
val outBound = json.parse(message).extract[OutBoundGetBankAccountBalanceById]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.getBankAccountBalanceById(outBound.balanceId,None).map(_._1.head)
obpMappedResponse.map(response => InBoundGetBankAccountBalanceById(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundGetBankAccountBalanceById(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("create_or_update_bank_account_balance")) {
val outBound = json.parse(message).extract[OutBoundCreateOrUpdateBankAccountBalance]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.createOrUpdateBankAccountBalance(outBound.bankId,outBound.accountId,outBound.balanceId,outBound.balanceType,outBound.balanceAmount,None).map(_._1.head)
obpMappedResponse.map(response => InBoundCreateOrUpdateBankAccountBalance(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundCreateOrUpdateBankAccountBalance(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("delete_bank_account_balance")) {
val outBound = json.parse(message).extract[OutBoundDeleteBankAccountBalance]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.deleteBankAccountBalance(outBound.balanceId,None).map(_._1.head)
obpMappedResponse.map(response => InBoundDeleteBankAccountBalance(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundDeleteBankAccountBalance(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = false
))
}
} else if (obpMessageId.contains("dynamic_entity_process")) {
val outBound = json.parse(message).extract[OutBoundDynamicEntityProcess]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.dynamicEntityProcess(outBound.operation,outBound.entityName,outBound.requestBody,outBound.entityId,None,None,None,false,None).map(_._1.head)
@ -3172,8 +3276,8 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
data = null
))
}
// ---------- created on 2025-04-07T14:53:47Z
//---------------- dynamic end ---------------------please don't modify this line
// ---------- created on 2025-05-27T08:15:58Z
//---------------- dynamic end ---------------------please don't modify this line
} else {
Future {
1

View File

@ -67,7 +67,7 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable {
val errorCodeExample = "INTERNAL-OBP-ADAPTER-6001: ..."
//---------------- dynamic start -------------------please don't modify this line
// ---------- created on 2025-05-22T11:32:05Z
// ---------- created on 2025-05-27T10:14:24Z
messageDocs += getAdapterInfoDoc
def getAdapterInfoDoc = MessageDoc(
@ -7176,6 +7176,36 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable {
response.map(convertToTuple[List[BankAccountBalanceTraitCommons]](callContext))
}
messageDocs += getBankAccountsBalancesByAccountIdsDoc
def getBankAccountsBalancesByAccountIdsDoc = MessageDoc(
process = "obp.getBankAccountsBalancesByAccountIds",
messageFormat = messageFormat,
description = "Get Bank Accounts Balances By Account Ids",
outboundTopic = None,
inboundTopic = None,
exampleOutboundMessage = (
OutBoundGetBankAccountsBalancesByAccountIds(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext,
accountIds=List(AccountId(accountIdExample.value)))
),
exampleInboundMessage = (
InBoundGetBankAccountsBalancesByAccountIds(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
status=MessageDocsSwaggerDefinitions.inboundStatus,
data=List( BankAccountBalanceTraitCommons(bankId=BankId(bankIdExample.value),
accountId=AccountId(accountIdExample.value),
balanceId=BalanceId(balanceIdExample.value),
balanceType=balanceTypeExample.value,
balanceAmount=BigDecimal(balanceAmountExample.value))))
),
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
override def getBankAccountsBalancesByAccountIds(accountIds: List[AccountId], callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = {
import com.openbankproject.commons.dto.{InBoundGetBankAccountsBalancesByAccountIds => InBound, OutBoundGetBankAccountsBalancesByAccountIds => OutBound}
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountIds)
val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts_balances_by_account_ids", req, callContext)
response.map(convertToTuple[List[BankAccountBalanceTraitCommons]](callContext))
}
messageDocs += getBankAccountBalanceByIdDoc
def getBankAccountBalanceByIdDoc = MessageDoc(
process = "obp.getBankAccountBalanceById",
@ -7266,8 +7296,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable {
response.map(convertToTuple[Boolean](callContext))
}
// ---------- created on 2025-05-22T11:32:05Z
//---------------- dynamic end ---------------------please don't modify this line
// ---------- created on 2025-05-27T10:14:24Z
//---------------- dynamic end ---------------------please don't modify this line
private val availableOperation = DynamicEntityOperation.values.map(it => s""""$it"""").mkString("[", ", ", "]")

View File

@ -26,25 +26,38 @@ TESOBE (http://www.tesobe.com/)
*/
package code.snippet
import code.api.util.APIUtil
import code.api.RequestHeader
import code.api.util.APIUtil.callEndpoint
import code.api.util.CustomJsonFormats
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
import code.api.v5_1_0.{ConsentInfoJsonV510, ConsentsInfoJsonV510}
import code.consumer.Consumers
import code.model.dataAccess.AuthUser
import code.util.Helper.{MdcLoggable, ObpS}
import code.util.HydraUtil.integrateWithHydra
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import net.liftweb.http.{RequestVar, S, SHtml}
import net.liftweb.common.Full
import net.liftweb.http.js.JsCmd
import net.liftweb.http.js.JsCmds._
import net.liftweb.http.{DeleteRequest, GetRequest, RequestVar, S, SHtml}
import net.liftweb.json
import net.liftweb.json.{Extraction, Formats, JNothing}
import net.liftweb.util.CssSel
import net.liftweb.util.Helpers._
import sh.ory.hydra.api.AdminApi
import sh.ory.hydra.model.{AcceptConsentRequest, RejectRequest}
import scala.jdk.CollectionConverters.seqAsJavaListConverter
import scala.xml.NodeSeq
class ConsentScreen extends MdcLoggable {
private object skipConsentScreenVar extends RequestVar(false)
private object consentChallengeVar extends RequestVar(ObpS.param("consent_challenge").getOrElse(""))
private object csrfVar extends RequestVar(ObpS.param("_csrf").getOrElse(""))
implicit val formats: Formats = CustomJsonFormats.formats
def submitAllowAction: Unit = {
integrateWithHydra match {
case true if !consentChallengeVar.isEmpty =>
@ -87,5 +100,75 @@ class ConsentScreen extends MdcLoggable {
"#deny_access_to_consent" #> SHtml.submit(s"Deny access", () => submitDenyAction)
}
}
def getConsents: CssSel = {
callEndpoint(Implementations5_1_0.getMyConsents, List("my", "consents"), GetRequest) match {
case Right(response) =>
tryo(json.parse(response).extract[ConsentsInfoJsonV510]) match {
case Full(consentsInfoJsonV510) =>
"#consent-table-body *" #> renderConsentRows(consentsInfoJsonV510.consents) &
"#flash-message *" #> NodeSeq.Empty
case _ =>
"#consent-table-body *" #> NodeSeq.Empty &
"#flash-message *" #> renderAlert("Failed to parse consent data.", isError = true)
}
case Left((msg, _)) =>
"#consent-table-body *" #> NodeSeq.Empty &
"#flash-message *" #> renderAlert(msg, isError = true)
}
}
private def renderAlert(msg: String, isError: Boolean): NodeSeq = {
val alertClass = if (isError) "alert-danger" else "alert-success"
<div class={"alert " + alertClass} role="alert">{msg}</div>
}
private def selfRevokeConsent(consentId: String): Either[(String, Int), String] = {
val addlParams = Map(RequestHeader.`Consent-Id` -> consentId)
callEndpoint(Implementations5_1_0.selfRevokeConsent, List("my", "consent", "current"), DeleteRequest, addlParams = addlParams)
}
private def refreshTable(): JsCmd = {
callEndpoint(Implementations5_1_0.getMyConsents, List("my", "consents"), GetRequest) match {
case Right(response) =>
tryo(json.parse(response).extract[ConsentsInfoJsonV510]) match {
case Full(consentsInfoJsonV510) =>
SetHtml("consent-table-body", renderConsentRows(consentsInfoJsonV510.consents))
case _ =>
SetHtml("consent-table-body", <tr><td colspan="6">Error parsing consent data</td></tr>)
}
case Left((msg, _)) =>
SetHtml("consent-table-body", <tr><td colspan="6">{msg}</td></tr>)
}
}
private def ShowMessage(msg: String, isError: Boolean): JsCmd = {
val alertClass = if (isError) "alert-danger" else "alert-success"
val html = <div class={"alert " + alertClass} role="alert">{msg}</div>
SetHtml("flash-message", html)
}
private def renderConsentRows(consents: List[ConsentInfoJsonV510]): NodeSeq = {
consents.map { consent =>
<tr class="consent-entry">
<td class="consent_reference_id">{consent.consent_reference_id}</td>
<td class="consumer-id">{consent.consumer_id}</td>
<td class="jwt-payload">{json.prettyRender(consent.jwt_payload.map(Extraction.decompose).openOr(JNothing))}</td>
<td class="status">{consent.status}</td>
<td class="api-standard">{consent.api_standard}</td>
<td>
{
SHtml.ajaxButton("Revoke", () => {
val result = selfRevokeConsent(consent.consent_id)
val message = result match {
case Left((msg, _)) => ShowMessage(msg, isError = true)
case Right(_) => ShowMessage(s"Consent (reference_id ${consent.consent_reference_id}) successfully revoked.", isError = false)
}
message & refreshTable()
})
}
</td>
</tr>
}
}
}

View File

@ -0,0 +1,51 @@
<!--
Open Bank Project - API
Copyright (C) 2011-2017, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
-->
<div data-lift="surround?with=default;at=content">
<div style="width: 90%; margin: 0 auto;" data-lift="ConsentScreen.getConsents">
<h2>Consents</h2>
<div id="flash-message"></div> <!-- Used to display AJAX messages -->
<table class="table">
<thead>
<tr>
<th>Consent Reference Id</th>
<th>Consumer Id</th>
<th>Jwt Payload</th>
<th>Status</th>
<th>Api Standard</th>
<th scope="col">Revoke</th>
</tr>
</thead>
<tbody id="consent-table-body">
<!-- Consent rows will be inserted here -->
</tbody>
</table>
</div>
</div>

View File

@ -119,6 +119,11 @@ Berlin 13359, Germany
<lift:loc locid="api_explorer">API Explorer</lift:loc>
</a>
</li>
<li class="navitem">
<a class="navlink api-explorer-link" href="/consents">
<lift:loc locid="Consents">Consents</lift:loc>
</a>
</li>
<li data-lift="Nav.item?name=Consumer%20Registration&showEvenIfRestricted=true" class="navitem">
<a id ="get-api-key-link" class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
</li>

View File

@ -26,10 +26,10 @@
package com.openbankproject.commons.dto
import com.openbankproject.commons.model._
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA
import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus
import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
import com.openbankproject.commons.model._
import net.liftweb.json.{JObject, JValue}
import java.util.Date
@ -392,6 +392,10 @@ case class OutBoundCreateTaxResidence(outboundAdapterCallContext: OutboundAdapte
case class InBoundCreateTaxResidence(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: TaxResidenceCommons) extends InBoundTrait[TaxResidenceCommons]
case class OutBoundGetBankAccountsBalancesByAccountIds (outboundAdapterCallContext: OutboundAdapterCallContext,
accountIds: List[AccountId]) extends TopicTrait
case class InBoundGetBankAccountsBalancesByAccountIds (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[BankAccountBalanceTraitCommons]) extends InBoundTrait[List[BankAccountBalanceTraitCommons]]
case class OutBoundGetTaxResidence(outboundAdapterCallContext: OutboundAdapterCallContext,
customerId: String) extends TopicTrait