Skip to content

Commit b6e4e38

Browse files
committed
Adding consent_items which is a denomralisation of the JWT so we don't
have to extract the JWT in order to query the bank_id (for get my consents at bank). Also pagination defaults to 50 rows.
1 parent b5dbcfd commit b6e4e38

9 files changed

Lines changed: 249 additions & 123 deletions

File tree

obp-api/src/main/scala/bootstrap/liftweb/Boot.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import code.branches.MappedBranch
6363
import code.cardattribute.MappedCardAttribute
6464
import code.cards.{MappedPhysicalCard, PinReset}
6565
import code.connectormethod.ConnectorMethod
66-
import code.consent.{ConsentRequest, MappedConsent}
66+
import code.consent.{ConsentRequest, MappedConsent, MappedConsentItems}
6767
import code.consumer.Consumers
6868
import code.model.Consumer
6969
import code.context.{MappedConsentAuthContext, MappedUserAuthContext, MappedUserAuthContextUpdate}
@@ -1120,6 +1120,7 @@ object ToSchemify {
11201120
MappedCustomerIdMapping,
11211121
MappedProductAttribute,
11221122
MappedConsent,
1123+
MappedConsentItems,
11231124
ConsentRequest,
11241125
MigrationScriptLog,
11251126
MethodRouting,

obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4601,7 +4601,7 @@ object SwaggerDefinitionsJSON {
46014601
last_action_date = dateExample.value,
46024602
last_usage_date = dateTimeExample.value,
46034603
jwt = jwtExample.value,
4604-
jwt_payload = Some(consentJWT),
4604+
jwt_payload = """{"createdByUserId":"user-id","sub":"subject","iss":"issuer","aud":"audience","jti":"jwt-id","iat":1611749820,"nbf":1611749820,"exp":1611753420,"request_headers":[],"name":null,"email":null,"entitlements":[],"views":[],"access":null}""",
46054605
api_standard = "Berlin Group",
46064606
api_version = "v1.3",
46074607
)

obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import code.api.v3_0_0.{CreateViewJsonV300, JSONFactory300}
2525
import code.api.v3_1_0.JSONFactory310._
2626
import code.bankconnectors.rest.RestConnector_vMar2019
2727
import code.bankconnectors.{Connector, LocalMappedConnector}
28-
import code.consent.{ConsentStatus, Consents, MappedConsent}
28+
import code.consent.{ConsentStatus, Consents, DoobieConsentQueries, MappedConsent}
2929
import code.consumer.Consumers
3030
import code.entitlement.Entitlement
3131
import code.loginattempts.LoginAttempt
@@ -3726,6 +3726,10 @@ trait APIMethods310 {
37263726
|
37273727
|${userAuthenticationMessage(true)}
37283728
|
3729+
|1 limit (for pagination: defaults to 50) eg:limit=200
3730+
|
3731+
|2 offset (for pagination: zero index, defaults to 0) eg: offset=10
3732+
|
37293733
""".stripMargin,
37303734
EmptyBody,
37313735
consentsJsonV310,
@@ -3739,12 +3743,32 @@ trait APIMethods310 {
37393743
lazy val getConsents: OBPEndpoint = {
37403744
case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
37413745
cc => implicit val ec = EndpointContext(Some(cc))
3746+
val url = cc.url
3747+
val limitParam = APIUtil.getHttpRequestUrlParam(url, "limit") match {
3748+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
3749+
case _ => 50
3750+
}
3751+
val offsetParam = APIUtil.getHttpRequestUrlParam(url, "offset") match {
3752+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
3753+
case _ => 0
3754+
}
37423755
for {
37433756
(Full(user), callContext) <- authenticatedAccess(cc)
37443757
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
3745-
consents <- Future(Consents.consentProvider.vend.getConsentsByUser(user.userId))
3758+
rows <- Future {
3759+
DoobieConsentQueries.getConsentsByUserAndBank(
3760+
userId = user.userId,
3761+
bankId = bankId.value,
3762+
status = None,
3763+
limit = limitParam,
3764+
offset = offsetParam,
3765+
sortField = "created_date",
3766+
sortDirection = "desc"
3767+
)
3768+
}
37463769
} yield {
3747-
(JSONFactory310.createConsentsJsonV310(consents), HttpCode.`200`(callContext))
3770+
val consents = rows.map(r => ConsentJsonV310(r.consentId, r.jwt.getOrElse(""), r.status))
3771+
(ConsentsJsonV310(consents), HttpCode.`200`(callContext))
37483772
}
37493773
}
37503774
}

obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import code.authtypevalidation.JsonAuthTypeValidation
4242
import code.bankconnectors.LocalMappedConnectorInternal._
4343
import code.bankconnectors.{Connector, DynamicConnector, InternalConnector, LocalMappedConnectorInternal}
4444
import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody}
45-
import code.consent.{ConsentStatus, Consents}
45+
import code.consent.{ConsentStatus, Consents, DoobieConsentQueries}
4646
import code.dynamicEntity.DynamicEntityCommons
4747
import code.dynamicMessageDoc.JsonDynamicMessageDoc
4848
import code.dynamicResourceDoc.JsonDynamicResourceDoc
@@ -11479,6 +11479,10 @@ trait APIMethods400 extends MdcLoggable {
1147911479
|
1148011480
|${userAuthenticationMessage(true)}
1148111481
|
11482+
|1 limit (for pagination: defaults to 50) eg:limit=200
11483+
|
11484+
|2 offset (for pagination: zero index, defaults to 0) eg: offset=10
11485+
|
1148211486
""".stripMargin,
1148311487
EmptyBody,
1148411488
consentsJsonV400,
@@ -11494,19 +11498,33 @@ trait APIMethods400 extends MdcLoggable {
1149411498
case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
1149511499
cc =>
1149611500
implicit val ec = EndpointContext(Some(cc))
11501+
val url = cc.url
11502+
val limitParam = getHttpRequestUrlParam(url, "limit") match {
11503+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
11504+
case _ => 50
11505+
}
11506+
val offsetParam = getHttpRequestUrlParam(url, "offset") match {
11507+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
11508+
case _ => 0
11509+
}
1149711510
for {
11498-
consents <- Future {
11499-
Consents.consentProvider.vend
11500-
.getConsentsByUser(cc.userId)
11501-
.sortBy(i => (i.creationDateTime, i.apiStandard))
11502-
.reverse
11511+
rows <- Future {
11512+
DoobieConsentQueries.getConsentsByUserAndBank(
11513+
userId = cc.userId,
11514+
bankId = bankId.value,
11515+
status = None,
11516+
limit = limitParam,
11517+
offset = offsetParam,
11518+
sortField = "created_date",
11519+
sortDirection = "desc"
11520+
)
1150311521
}
1150411522
} yield {
11505-
val consentsOfBank = Consent.filterByBankId(consents, bankId)
11506-
(
11507-
JSONFactory400.createConsentsJsonV400(consentsOfBank),
11508-
HttpCode.`200`(cc)
11509-
)
11523+
val consents = rows.map(r => ConsentJsonV400(
11524+
r.consentId, r.jwt.getOrElse(""), r.status,
11525+
r.apiStandard.getOrElse(""), r.apiVersion.getOrElse("")
11526+
))
11527+
(ConsentsJsonV400(consents), HttpCode.`200`(cc))
1151011528
}
1151111529
}
1151211530
}

obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,10 +1803,23 @@ trait APIMethods510 {
18031803
"Get My Consents at Bank",
18041804
s"""
18051805
|
1806-
|This endpoint gets the Consents created by a current User.
1806+
|This endpoint gets the Consents created by a current User at the specified Bank.
18071807
|
18081808
|${userAuthenticationMessage(true)}
18091809
|
1810+
|1 limit (for pagination: defaults to 50) eg:limit=200
1811+
|
1812+
|2 offset (for pagination: zero index, defaults to 0) eg: offset=10
1813+
|
1814+
|3 status (ignore if omitted)
1815+
|
1816+
|4 sort_by (defaults to created_date:desc) eg: sort_by=created_date:desc
1817+
|
1818+
|Note: This endpoint only returns consents that explicitly reference the specified BANK_ID.
1819+
|Consents created before the consent_items join table was introduced will not appear in results.
1820+
|
1821+
|eg: /banks/BANK_ID/my/consents?limit=10&offset=0&sort_by=created_date:desc
1822+
|
18101823
""".stripMargin,
18111824
EmptyBody,
18121825
consentsInfoJsonV510,
@@ -1821,26 +1834,42 @@ trait APIMethods510 {
18211834
case "banks" :: BankId(bankId) :: "my" :: "consents" :: Nil JsonGet _ => {
18221835
cc =>
18231836
implicit val ec = EndpointContext(Some(cc))
1837+
val url = cc.url
1838+
val limitParam = getHttpRequestUrlParam(url, "limit") match {
1839+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(50)
1840+
case _ => 50
1841+
}
1842+
val offsetParam = getHttpRequestUrlParam(url, "offset") match {
1843+
case s if s.nonEmpty => scala.util.Try(s.toInt).getOrElse(0)
1844+
case _ => 0
1845+
}
1846+
val statusParam = getHttpRequestUrlParam(url, "status") match {
1847+
case s if s.nonEmpty => Some(s)
1848+
case _ => None
1849+
}
1850+
val sortByParam = getHttpRequestUrlParam(url, "sort_by") match {
1851+
case s if s.nonEmpty => s
1852+
case _ => "created_date:desc"
1853+
}
1854+
val sortParts = sortByParam.split(":").map(_.trim.toLowerCase)
1855+
val sortField = sortParts(0)
1856+
val sortDirection = sortParts.lift(1).getOrElse("desc")
18241857
for {
1858+
(Full(u), callContext) <- authenticatedAccess(cc)
18251859
rows <- Future {
1826-
DoobieConsentQueries.getAllConsentsByUser(cc.userId)
1860+
DoobieConsentQueries.getConsentsByUserAndBank(
1861+
userId = u.userId,
1862+
bankId = bankId.value,
1863+
status = statusParam,
1864+
limit = limitParam,
1865+
offset = offsetParam,
1866+
sortField = sortField,
1867+
sortDirection = sortDirection
1868+
)
18271869
}
18281870
} yield {
1829-
// Bank filtering requires JWT decoding — done in Scala
1830-
val filteredRows = rows.filter { row =>
1831-
row.jwt.exists { jwt =>
1832-
val jwtPayload: Box[ConsentJWT] = JwtUtil.getSignedPayloadAsJson(jwt).map(parse(_).extract[ConsentJWT])
1833-
jwtPayload match {
1834-
case Full(c) if c.views.isEmpty => true
1835-
case Full(c) if c.views.map(_.bank_id).contains(bankId.value) => true
1836-
case Full(c) if c.entitlements.exists(_.bank_id.isEmpty()) => true
1837-
case Full(c) if c.entitlements.map(_.bank_id).contains(bankId.value) => true
1838-
case _ => false
1839-
}
1840-
}
1841-
}
1842-
val consents = filteredRows.map(rowToConsentInfoJsonV510)
1843-
(ConsentsInfoJsonV510(consents), HttpCode.`200`(cc))
1871+
val consents = rows.map(rowToConsentInfoJsonV510)
1872+
(ConsentsInfoJsonV510(consents), HttpCode.`200`(callContext))
18441873
}
18451874
}
18461875
}
@@ -1903,7 +1932,7 @@ trait APIMethods510 {
19031932
val sortDirection = sortParts.lift(1).getOrElse("desc")
19041933
for {
19051934
(Full(u), callContext) <- authenticatedAccess(cc)
1906-
(rows, _) <- Future {
1935+
rows <- Future {
19071936
DoobieConsentQueries.getConsentsByUser(
19081937
userId = u.userId,
19091938
status = statusParam,
@@ -1920,14 +1949,6 @@ trait APIMethods510 {
19201949
}
19211950

19221951
private def rowToConsentInfoJsonV510(row: DoobieConsentQueries.ConsentRow): ConsentInfoJsonV510 = {
1923-
// Use pre-computed jwt_payload from DB; fall back to parsing jwt if not yet populated
1924-
val jwtPayload: Box[ConsentJWT] = row.jwtPayload match {
1925-
case Some(payload) => tryo(parse(payload).extract[ConsentJWT])
1926-
case None => row.jwt match {
1927-
case Some(jwt) => JwtUtil.getSignedPayloadAsJson(jwt).map(parse(_).extract[ConsentJWT])
1928-
case None => Empty
1929-
}
1930-
}
19311952
ConsentInfoJsonV510(
19321953
consent_reference_id = row.consentReferenceId.toString,
19331954
consent_id = row.consentId,
@@ -1939,7 +1960,7 @@ trait APIMethods510 {
19391960
last_usage_date =
19401961
row.lastUsageDate.map(d => new java.text.SimpleDateFormat(DateWithSeconds).format(d)).orNull,
19411962
jwt = row.jwt.orNull,
1942-
jwt_payload = jwtPayload,
1963+
jwt_payload = row.jwtPayload.orNull,
19431964
api_standard = row.apiStandard.orNull,
19441965
api_version = row.apiVersion.orNull
19451966
)

obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ case class ConsentInfoJsonV510(consent_reference_id: String,
172172
last_action_date: String,
173173
last_usage_date: String,
174174
jwt: String,
175-
jwt_payload: Box[ConsentJWT],
175+
jwt_payload: String,
176176
api_standard: String,
177177
api_version: String,
178178
)
@@ -1007,9 +1007,6 @@ object JSONFactory510 extends CustomJsonFormats with MdcLoggable {
10071007

10081008
ConsentsInfoJsonV510(
10091009
consents.map { c =>
1010-
val jwtPayload: Box[ConsentJWT] =
1011-
JwtUtil.getSignedPayloadAsJson(c.jsonWebToken).map(parse(_).extract[ConsentJWT])
1012-
10131010
ConsentInfoJsonV510(
10141011
consent_reference_id = c.consentReferenceId,
10151012
consent_id = c.consentId,
@@ -1021,7 +1018,7 @@ object JSONFactory510 extends CustomJsonFormats with MdcLoggable {
10211018
last_usage_date =
10221019
if (c.usesSoFarTodayCounterUpdatedAt != null) new SimpleDateFormat(DateWithSeconds).format(c.usesSoFarTodayCounterUpdatedAt) else null,
10231020
jwt = c.jsonWebToken,
1024-
jwt_payload = jwtPayload,
1021+
jwt_payload = null,
10251022
api_standard = c.apiStandard,
10261023
api_version = c.apiVersion
10271024
)

0 commit comments

Comments
 (0)