Skip to content

Commit 086793a

Browse files
authored
Merge pull request #2805 from simonredfern/develop
v7.0.0 corePrivateAccountsAllBanks
2 parents 81a280e + 2f8549a commit 086793a

2 files changed

Lines changed: 124 additions & 2 deletions

File tree

obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import code.api.util.http4s.{ErrorResponseConverter, Http4sRequestAttributes, Id
1414
import code.api.util.http4s.Http4sRequestAttributes.{EndpointHelpers, RequestOps}
1515
import code.api.util.newstyle.ViewNewStyle
1616
import code.api.v1_4_0.JSONFactory1_4_0
17+
import code.api.v2_0_0.AccountsHelper.accountTypeFilterText
1718
import code.api.v2_0_0.{BasicViewJson, CreateEntitlementJSON, JSONFactory200}
1819
import code.api.v4_0_0.JSONFactory400
1920
import code.api.v6_0_0.{BasicAccountJsonV600, BasicAccountsJsonV600, BankJsonV600, CacheConfigJsonV600, CacheInfoJsonV600, CacheNamespaceInfoJsonV600, CacheNamespaceJsonV600, CacheNamespacesJsonV600, ConnectorInfoJsonV600, ConnectorsJsonV600, DatabasePoolInfoJsonV600, FeaturesJsonV600, InMemoryCacheStatusJsonV600, JSONFactory600, RedisCacheStatusJsonV600, StoredProcedureConnectorHealthJsonV600, UserV600}
@@ -33,7 +34,7 @@ import code.metadata.tags.Tags
3334
import code.views.Views
3435
import code.accountattribute.AccountAttributeX
3536
import code.users.{Users => UserVend}
36-
import com.openbankproject.commons.model.{AccountId, BankId, BankIdAccountId, CounterpartyId, CustomerId, ListResult, TransactionRequestType, ViewId}
37+
import com.openbankproject.commons.model.{AccountId, BankId, BankIdAccountId, CoreAccount, CounterpartyId, CustomerId, ListResult, TransactionRequestType, ViewId}
3738
import com.openbankproject.commons.model.enums.ChallengeType
3839
import com.github.dwickern.macros.NameOf.nameOf
3940
import com.openbankproject.commons.ExecutionContext.Implicits.global
@@ -344,6 +345,62 @@ object Http4s700 {
344345
http4sPartialFunction = Some(getCoreAccountById)
345346
)
346347

348+
// ─── corePrivateAccountsAllBanks (v7) ─────────────────────────────────────
349+
// Same semantics as v3.0.0 /my/accounts but with renamed fields so callers
350+
// can read the (bank_id, account_id, view_id) tuple without remapping.
351+
// v3: { id, ..., views: [ { id, ... } ] }
352+
// v7: { account_id, ..., views: [ { view_id, ... } ] }
353+
354+
val corePrivateAccountsAllBanks: HttpRoutes[IO] = HttpRoutes.of[IO] {
355+
case req @ GET -> `prefixPath` / "my" / "accounts" =>
356+
EndpointHelpers.withUser(req) { (user, cc) =>
357+
for {
358+
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(user)
359+
(coreAccounts, _) <- NewStyle.function.getCoreBankAccountsFuture(availablePrivateAccounts, Some(cc))
360+
filtered = filterCoreAccountsByType(coreAccounts, req)
361+
} yield JSONFactory700.createCoreAccountsByCoreAccountsJsonV700(filtered, user)
362+
}
363+
}
364+
365+
resourceDocs += ResourceDoc(
366+
null,
367+
implementedInApiVersion,
368+
nameOf(corePrivateAccountsAllBanks),
369+
"GET",
370+
"/my/accounts",
371+
"Get Accounts at all Banks (private)",
372+
s"""Returns the list of accounts containing private views for the user.
373+
|Each account lists the views available to the user.
374+
|
375+
|This endpoint is the v7.0.0 version of `/obp/v3.0.0/my/accounts` with
376+
|renamed identifier fields: `account_id` (was `id`) and `view_id` (was `id` on each view)
377+
|so the response gives the `(bank_id, account_id, view_id)` tuple directly.
378+
|
379+
|${accountTypeFilterText("/my/accounts")}
380+
|
381+
|${userAuthenticationMessage(true)}
382+
|""",
383+
EmptyBody,
384+
JSONFactory700.coreAccountsJsonV700Example,
385+
List($AuthenticatedUserIsRequired, UnknownError),
386+
List(apiTagAccount, apiTagPSD2AIS, apiTagPrivateData, apiTagPsd2),
387+
None,
388+
http4sPartialFunction = Some(corePrivateAccountsAllBanks)
389+
)
390+
391+
private def filterCoreAccountsByType(accounts: List[CoreAccount], req: Request[IO]): List[CoreAccount] = {
392+
val qp = req.uri.query.multiParams
393+
val filters = qp.get("account_type_filter").toList.flatMap(_.flatMap(_.split(","))).filter(_.nonEmpty)
394+
val filtersOperation = qp.get("account_type_filter_operation").flatMap(_.headOption).getOrElse("INCLUDE")
395+
accounts.filter { account =>
396+
(filters, filtersOperation) match {
397+
case (f, "INCLUDE") if f.nonEmpty => f.contains(account.accountType)
398+
case (f, "EXCLUDE") if f.nonEmpty => !f.contains(account.accountType)
399+
case _ => true
400+
}
401+
}
402+
}
403+
347404
// Category: withView (user + account + view resolved from BANK_ID + ACCOUNT_ID + VIEW_ID by middleware)
348405
val getPrivateAccountByIdFull: HttpRoutes[IO] = HttpRoutes.of[IO] {
349406
case req @ GET -> `prefixPath` / "banks" / _ / "accounts" / _ / viewIdStr / "account" =>

obp-api/src/main/scala/code/api/v7_0_0/JSONFactory7.0.0.scala

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400, PostSimpleCou
88
import code.bankconnectors.Connector
99
import code.customer.CustomerX
1010
import code.util.Helper.MdcLoggable
11-
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, TransactionRequest, TransactionRequestCommonBodyJSON}
11+
import code.views.Views
12+
import com.openbankproject.commons.model.{AccountId, AccountRoutingJsonV121, AmountOfMoneyJsonV121, BankId, BankIdAccountId, CoreAccount, TransactionRequest, TransactionRequestCommonBodyJSON, User}
1213
import com.openbankproject.commons.util.ApiVersion
1314
import net.liftweb.common.Full
1415

@@ -969,4 +970,68 @@ object JSONFactory700 extends MdcLoggable with code.api.util.CustomJsonFormats {
969970
}
970971
}
971972
}
973+
974+
// ─── Core accounts at all banks (v7 rename: id → account_id / views[].id → view_id) ──
975+
976+
case class ViewBasicV700(
977+
view_id: String,
978+
short_name: String,
979+
description: String,
980+
is_public: Boolean
981+
)
982+
983+
case class CoreAccountJsonV700(
984+
account_id: String,
985+
label: String,
986+
bank_id: String,
987+
account_type: String,
988+
account_routings: List[AccountRoutingJsonV121],
989+
views: List[ViewBasicV700]
990+
)
991+
992+
case class CoreAccountsJsonV700(accounts: List[CoreAccountJsonV700])
993+
994+
def createCoreAccountsByCoreAccountsJsonV700(
995+
coreAccounts: List[CoreAccount],
996+
user: User
997+
): CoreAccountsJsonV700 =
998+
CoreAccountsJsonV700(coreAccounts.map { coreAccount =>
999+
CoreAccountJsonV700(
1000+
account_id = coreAccount.id,
1001+
label = coreAccount.label,
1002+
bank_id = coreAccount.bankId,
1003+
account_type = coreAccount.accountType,
1004+
account_routings = coreAccount.accountRoutings.map(r =>
1005+
AccountRoutingJsonV121(r.scheme, r.address)),
1006+
views = Views.views.vend
1007+
.privateViewsUserCanAccessForAccount(
1008+
user, BankIdAccountId(BankId(coreAccount.bankId), AccountId(coreAccount.id)))
1009+
.filter(_.isPrivate)
1010+
.map(v => ViewBasicV700(
1011+
view_id = v.viewId.value,
1012+
short_name = v.name,
1013+
description = v.description,
1014+
is_public = v.isPublic
1015+
))
1016+
)
1017+
})
1018+
1019+
lazy val viewBasicV700Example = ViewBasicV700(
1020+
view_id = "owner",
1021+
short_name = "Owner",
1022+
description = "Owner View",
1023+
is_public = false
1024+
)
1025+
1026+
lazy val coreAccountJsonV700Example = CoreAccountJsonV700(
1027+
account_id = "f026fbd3-d1ea-496b-a853-3cbe65629881",
1028+
label = "Account 1",
1029+
bank_id = "smnr.bnk.1",
1030+
account_type = "330",
1031+
account_routings = List(AccountRoutingJsonV121("IBAN", "DE89 3704 0044 0532 0130 00")),
1032+
views = List(viewBasicV700Example)
1033+
)
1034+
1035+
lazy val coreAccountsJsonV700Example =
1036+
CoreAccountsJsonV700(accounts = List(coreAccountJsonV700Example))
9721037
}

0 commit comments

Comments
 (0)