mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 17:17:09 +00:00
commit
331908d853
@ -177,7 +177,7 @@ The two user models are now called AuthUser and ResourceUser
|
||||
* Answer Transaction Request Challenge (updated)
|
||||
* Get Transaction Requests (updated)
|
||||
* Get Roles (new)
|
||||
* Get Entitlements By Bank And User (naaew)
|
||||
* Get Entitlements By Bank And User (new)
|
||||
* Get Consumer (App) (new)
|
||||
* Get Consumers (App) (new)
|
||||
* Enable Disable Consumers (Apps) (new)
|
||||
|
||||
@ -353,6 +353,9 @@ object GatewayLogin extends RestHelper with MdcLoggable {
|
||||
consumerId=Some(consumerId),
|
||||
Some(Helpers.randomString(40).toLowerCase),
|
||||
Some(Helpers.randomString(40).toLowerCase),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(true),
|
||||
name = Some(consumerName),
|
||||
appType = None,
|
||||
|
||||
@ -29,6 +29,8 @@ package code.api
|
||||
import java.net.URI
|
||||
|
||||
import code.api.util.{APIUtil, CallContext, ErrorMessages, JwtUtil}
|
||||
import code.consumer.Consumers
|
||||
import code.model.Consumer
|
||||
import code.users.Users
|
||||
import code.util.Helper.MdcLoggable
|
||||
import com.nimbusds.jwt.JWTClaimsSet
|
||||
@ -36,6 +38,7 @@ import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet
|
||||
import com.openbankproject.commons.model.User
|
||||
import net.liftweb.common._
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.util.Helpers
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
@ -232,12 +235,52 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This function creates a consumer based on "azp", "sub", "iss", "name" and "email" fields
|
||||
* Please note that a user must be created before consumer.
|
||||
* Unique criteria to decide do we create or get a consumer is pair o values: < sub : azp > i.e.
|
||||
* We cannot find consumer by sub and azp => Create
|
||||
* We can find consumer by sub and azp => Get
|
||||
* @param idToken Google's response example:
|
||||
* {
|
||||
* "access_token": "ya29.GluUBg5DflrJciFikW5hqeKEp9r1whWnU5x2JXCm9rKkRMs2WseXX8O5UugFMDsIKuKCZlE7tTm1fMII_YYpvcMX6quyR5DXNHH8Lbx5TrZN__fA92kszHJEVqPc",
|
||||
* "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA4ZDMyNDVjNjJmODZiNjM2MmFmY2JiZmZlMWQwNjk4MjZkZDFkYzEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTM5NjY4NTQyNDU3ODA4OTI5NTkiLCJlbWFpbCI6Im1hcmtvLm1pbGljLnNyYmlqYUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6Im5HS1JUb0tOblZBMjhINk1od1hCeHciLCJuYW1lIjoiTWFya28gTWlsacSHIiwicGljdHVyZSI6Imh0dHBzOi8vbGg1Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tWGQ0NGhuSjZURG8vQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQUt4cndjYWR3emhtNE40dFdrNUU4QXZ4aS1aSzZrczRxZy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiTWFya28iLCJmYW1pbHlfbmFtZSI6Ik1pbGnEhyIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTQ3NzA1NjkxLCJleHAiOjE1NDc3MDkyOTF9.iUxhF_SU2vi76zPuRqAKJvFOzpb_EeP3lc5u9FO9o5xoXzVq3QooXexTfK2f1YAcWEy9LSftA34PB0QTuCZpkQChZVM359n3a3hplf6oWWkBXZN2_IG10NwEH4g0VVBCsjWBDMp6lvepN_Zn15x8opUB7272m4-smAou_WmUPTeivXRF8yPcp4J55DigcY31YP59dMQr2X-6Rr1vCRnJ6niqqJ1UDldfsgt4L7dXmUCnkDdXHwEQAZwbKbR4dUoEha3QeylCiBErmLdpIyqfKECphC6piGXZB-rRRqLz41WNfuF-3fswQvGmIkzTJDR7lQaletMp7ivsfVw8N5jFxg",
|
||||
* "expires_in": 3600,
|
||||
* "token_type": "Bearer",
|
||||
* "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
|
||||
* "refresh_token": "1/HkTtUahtUTdG7D6urpPNz6g-_qufF-Y1YppcBf0v3Cs"
|
||||
* }
|
||||
* @return an existing or a new consumer
|
||||
*/
|
||||
def getOrCreateConsumerFuture(idToken: String, userId: Box[String]): Box[Consumer] = {
|
||||
val azp = getClaim(name = "azp", idToken = idToken)
|
||||
val iss = getClaim(name = "iss", idToken = idToken)
|
||||
val sub = getClaim(name = "sub", idToken = idToken)
|
||||
val email = getClaim(name = "email", idToken = idToken)
|
||||
val name = getClaim(name = "name", idToken = idToken)
|
||||
Consumers.consumers.vend.getOrCreateConsumer(
|
||||
consumerId = None,
|
||||
key = Some(Helpers.randomString(40).toLowerCase),
|
||||
secret = Some(Helpers.randomString(40).toLowerCase),
|
||||
azp = azp,
|
||||
iss = iss,
|
||||
sub = sub,
|
||||
Some(true),
|
||||
name = name,
|
||||
appType = None,
|
||||
description = iss.map(v => "Via " + v),
|
||||
developerEmail = email,
|
||||
redirectURL = None,
|
||||
createdByUserId = userId.toOption
|
||||
)
|
||||
}
|
||||
|
||||
def applyRules(value: String, cc: CallContext): (Box[User], Some[CallContext]) = {
|
||||
validateIdToken(value) match {
|
||||
case Full(_) =>
|
||||
val user = Google.getOrCreateResourceUser(value)
|
||||
(user, Some(cc))
|
||||
val consumer = Google.getOrCreateConsumerFuture(value, user.map(_.userId))
|
||||
(user, Some(cc.copy(consumer = consumer)))
|
||||
case ParamFailure(a, b, c, apiFailure : APIFailure) =>
|
||||
(ParamFailure(a, b, c, apiFailure : APIFailure), Some(cc))
|
||||
case Failure(msg, t, c) =>
|
||||
@ -251,8 +294,9 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
case Full(_) =>
|
||||
for {
|
||||
user <- Google.getOrCreateResourceUserFuture(value)
|
||||
consumer <- Future{Google.getOrCreateConsumerFuture(value, user.map(_.userId))}
|
||||
} yield {
|
||||
(user, Some(cc))
|
||||
(user, Some(cc.copy(consumer = consumer)))
|
||||
}
|
||||
case ParamFailure(a, b, c, apiFailure : APIFailure) =>
|
||||
Future((ParamFailure(a, b, c, apiFailure : APIFailure), Some(cc)))
|
||||
|
||||
@ -15,7 +15,7 @@ import code.api.v3_0_0.JSONFactory300.createBranchJsonV300
|
||||
import code.api.v3_0_0.custom.JSONFactoryCustom300
|
||||
import code.api.v3_0_0.{LobbyJsonV330, _}
|
||||
import code.api.v3_1_0.{AccountBalanceV310, AccountsBalancesV310Json, BadLoginStatusJson, ContactDetailsJson, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _}
|
||||
import code.api.v4_0_0.{APIInfoJson400, EnergySource400, HostedAt400, HostedBy400, ModeratedCoreAccountJsonV400}
|
||||
import code.api.v4_0_0.{APIInfoJson400, AccountTagJSON, AccountTagsJSON, EnergySource400, HostedAt400, HostedBy400, ModeratedCoreAccountJsonV400, PostAccountTagJSON}
|
||||
import code.branches.Branches.{Branch, DriveUpString, LobbyString}
|
||||
import code.consent.ConsentStatus
|
||||
import code.sandbox.SandboxData
|
||||
@ -505,6 +505,9 @@ object SwaggerDefinitionsJSON {
|
||||
val postTransactionTagJSON = PostTransactionTagJSON(
|
||||
value = "String"
|
||||
)
|
||||
val postAccountTagJSON = PostAccountTagJSON(
|
||||
value = "String"
|
||||
)
|
||||
val aliasJSON = AliasJSON(
|
||||
alias = "String"
|
||||
)
|
||||
@ -895,6 +898,16 @@ object SwaggerDefinitionsJSON {
|
||||
tags = List(transactionTagJSON)
|
||||
)
|
||||
|
||||
val accountTagJSON = AccountTagJSON(
|
||||
id = "5995d6a2-01b3-423c-a173-5481df49bdaf",
|
||||
value = "OBP",
|
||||
date = DateWithDayExampleObject,
|
||||
user = userJSONV121
|
||||
)
|
||||
val accountTagsJSON = AccountTagsJSON(
|
||||
tags = List(accountTagJSON)
|
||||
)
|
||||
|
||||
val transactionMetadataJSON = TransactionMetadataJSON(
|
||||
narrative = "NONE",
|
||||
comments = List(transactionCommentJSON),
|
||||
@ -3248,15 +3261,17 @@ object SwaggerDefinitionsJSON {
|
||||
)
|
||||
|
||||
val postConsentEmailJsonV310 = PostConsentEmailJsonV310(
|
||||
`for` = "ALL_MY_ACCOUNTS",
|
||||
view = "owner",
|
||||
email = "marko@tesobe.com"
|
||||
everything = false,
|
||||
views = List(ViewJsonV400(bankIdExample.value, accountIdExample.value, viewIdExample.value)),
|
||||
entitlements = List(EntitlementJsonV400(bankIdExample.value, "CanQueryOtherUser")),
|
||||
email = emailExample.value
|
||||
)
|
||||
|
||||
val postConsentPhoneJsonV310 = PostConsentPhoneJsonV310(
|
||||
`for` = "ALL_MY_ACCOUNTS",
|
||||
view = "owner",
|
||||
phone_number = "493081453994"
|
||||
everything = false,
|
||||
views = List(ViewJsonV400(bankIdExample.value, accountIdExample.value, viewIdExample.value)),
|
||||
entitlements = List(EntitlementJsonV400(bankIdExample.value, "CanQueryOtherUser")),
|
||||
phone_number = mobileNumberExample.value
|
||||
)
|
||||
|
||||
val consentsJsonV310 = ConsentsJsonV310(List(consentJsonV310))
|
||||
@ -3367,7 +3382,7 @@ object SwaggerDefinitionsJSON {
|
||||
views_basic = List(viewBasicV300),
|
||||
account_attributes = List(accountAttributeResponseJson)
|
||||
)
|
||||
val newModeratedCoreAccountJsonV400 = ModeratedCoreAccountJsonV400(
|
||||
val moderatedCoreAccountJsonV400 = ModeratedCoreAccountJsonV400(
|
||||
id = accountIdExample.value,
|
||||
bank_id= bankIdExample.value,
|
||||
label= labelExample.value,
|
||||
@ -3378,7 +3393,7 @@ object SwaggerDefinitionsJSON {
|
||||
account_routings = List(accountRoutingJsonV121),
|
||||
views_basic = List(viewBasicV300),
|
||||
account_attributes = List(accountAttributeResponseJson),
|
||||
tags = List(transactionTagJSON)
|
||||
tags = List(accountTagJSON)
|
||||
)
|
||||
|
||||
val postHistoricalTransactionJson = PostHistoricalTransactionJson(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package code.api.util
|
||||
|
||||
import code.api.v3_1_0.{EntitlementJsonV400, PostConsentBodyCommonJson, ViewJsonV400}
|
||||
import code.consent.{ConsentStatus, Consents, MappedConsent}
|
||||
import code.consumer.Consumers
|
||||
import code.entitlement.Entitlement
|
||||
@ -13,6 +14,7 @@ import net.liftweb.json.JsonParser.ParseException
|
||||
import net.liftweb.json.{Extraction, MappingException, compactRender}
|
||||
import net.liftweb.mapper.By
|
||||
|
||||
import scala.collection.immutable.List
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
|
||||
@ -310,21 +312,30 @@ object Consent {
|
||||
}
|
||||
|
||||
|
||||
def createConsentJWT(user: User, viewId: String, secret: String, consentId: String): String = {
|
||||
def createConsentJWT(user: User,
|
||||
consent: PostConsentBodyCommonJson,
|
||||
secret: String,
|
||||
consentId: String): String = {
|
||||
val consumerKey = Consumer.findAll(By(Consumer.createdByUserId, user.userId)).map(_.key.get).headOption.getOrElse("")
|
||||
val currentTimeInSeconds = System.currentTimeMillis / 1000
|
||||
val views: Box[List[ConsentView]] = {
|
||||
Views.views.vend.getPermissionForUser(user) map {
|
||||
_.views map {
|
||||
view =>
|
||||
ConsentView(
|
||||
bank_id = view.bankId.value,
|
||||
account_id = view.accountId.value,
|
||||
view_id = viewId
|
||||
)
|
||||
}
|
||||
val views: Seq[ConsentView] =
|
||||
for {
|
||||
view <- Views.views.vend.getPermissionForUser(user).map(_.views).getOrElse(Nil)
|
||||
if consent.everything || consent.views.exists(_ == ViewJsonV400(view.bankId.value,view.accountId.value, view.viewId.value))
|
||||
} yield {
|
||||
ConsentView(
|
||||
bank_id = view.bankId.value,
|
||||
account_id = view.accountId.value,
|
||||
view_id = view.viewId.value
|
||||
)
|
||||
}
|
||||
val entitlements: Seq[Role] =
|
||||
for {
|
||||
entitlement <- Entitlement.entitlement.vend.getEntitlementsByUserId(user.userId).getOrElse(Nil)
|
||||
if consent.everything || consent.entitlements.exists(_ == EntitlementJsonV400(entitlement.bankId,entitlement.roleName))
|
||||
} yield {
|
||||
Role(entitlement.roleName, entitlement.bankId)
|
||||
}
|
||||
}.map(_.distinct)
|
||||
val json = ConsentJWT(
|
||||
createdByUserId=user.userId,
|
||||
sub=APIUtil.generateUUID(),
|
||||
@ -336,8 +347,8 @@ object Consent {
|
||||
exp=currentTimeInSeconds + 3600,
|
||||
name=None,
|
||||
email=None,
|
||||
entitlements=Nil,
|
||||
views=views.getOrElse(Nil)
|
||||
entitlements=entitlements.toList,
|
||||
views=views.toList
|
||||
)
|
||||
|
||||
implicit val formats = CustomJsonFormats.formats
|
||||
|
||||
@ -32,8 +32,10 @@ object PegdownOptions {
|
||||
// convertPegdownToHtmlTweaked not support insert image, so here manual convert to html img tag
|
||||
private def convertImgTag(markdown: String) = markdown.stripMargin.replaceAll("""!\[(.*)\]\((.*) =(.*?)x(.*?)\)""", """<img alt="$1" src="$2" width="$3" height="$4" />""")
|
||||
|
||||
def convertMarkdownToHtml(description: String): String = {
|
||||
def convertGitHubDocMarkdownToHtml(description: String): String = {
|
||||
val options = new MutableDataSet()
|
||||
import com.vladsch.flexmark.parser.ParserEmulationProfile
|
||||
options.setFrom(ParserEmulationProfile.GITHUB_DOC)
|
||||
val parser = Parser.builder(options).build
|
||||
val renderer = HtmlRenderer.builder(options).build
|
||||
val document = parser.parse(description.stripMargin)
|
||||
|
||||
@ -3390,7 +3390,7 @@ trait APIMethods310 {
|
||||
createdConsent <- Future(Consents.consentProvider.vend.createConsent(user)) map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
}
|
||||
consentJWT = Consent.createConsentJWT(user, consentJson.view, createdConsent.secret, createdConsent.consentId)
|
||||
consentJWT = Consent.createConsentJWT(user, consentJson, createdConsent.secret, createdConsent.consentId)
|
||||
_ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
}
|
||||
|
||||
@ -490,27 +490,32 @@ case class MeetingJsonV310(
|
||||
case class MeetingsJsonV310(
|
||||
meetings: List[MeetingJsonV310]
|
||||
)
|
||||
|
||||
case class EntitlementJsonV400(bank_id: String, role_name: String)
|
||||
case class ViewJsonV400(bank_id: String, account_id: String, view_id: String)
|
||||
trait PostConsentCommonBody{
|
||||
val `for`: String
|
||||
val view: String
|
||||
val everything: Boolean
|
||||
val views: List[ViewJsonV400]
|
||||
val entitlements: List[EntitlementJsonV400]
|
||||
}
|
||||
|
||||
case class PostConsentBodyCommonJson(
|
||||
`for`: String,
|
||||
view: String
|
||||
everything: Boolean,
|
||||
views: List[ViewJsonV400],
|
||||
entitlements: List[EntitlementJsonV400]
|
||||
) extends PostConsentCommonBody
|
||||
|
||||
case class PostConsentEmailJsonV310(
|
||||
`for`: String,
|
||||
view: String,
|
||||
email: String
|
||||
everything: Boolean,
|
||||
views: List[ViewJsonV400],
|
||||
entitlements: List[EntitlementJsonV400],
|
||||
email: String
|
||||
) extends PostConsentCommonBody
|
||||
|
||||
case class PostConsentPhoneJsonV310(
|
||||
`for`: String,
|
||||
view: String,
|
||||
phone_number: String
|
||||
everything: Boolean,
|
||||
views: List[ViewJsonV400],
|
||||
entitlements: List[EntitlementJsonV400],
|
||||
phone_number: String
|
||||
) extends PostConsentCommonBody
|
||||
|
||||
case class ConsentJsonV310(consent_id: String, jwt: String, status: String)
|
||||
|
||||
@ -1117,8 +1117,8 @@ trait APIMethods400 {
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|Authentication is required as the tag is linked with the user.""",
|
||||
postTransactionTagJSON,
|
||||
transactionTagJSON,
|
||||
postAccountTagJSON,
|
||||
accountTagJSON,
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
BankAccountNotFound,
|
||||
@ -1149,7 +1149,7 @@ trait APIMethods400 {
|
||||
i => (connectorEmptyResponse(i, callContext), callContext)
|
||||
}
|
||||
} yield {
|
||||
(JSONFactory.createTransactionTagJSON(postedTag), HttpCode.`201`(callContext))
|
||||
(JSONFactory400.createAccountTagJSON(postedTag), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1209,7 +1209,7 @@ trait APIMethods400 {
|
||||
|
|
||||
|Authentication is required as the tag is linked with the user.""",
|
||||
emptyObjectJson,
|
||||
transactionTagJSON,
|
||||
accountTagsJSON,
|
||||
List(
|
||||
BankAccountNotFound,
|
||||
NoViewPermission,
|
||||
@ -1234,7 +1234,7 @@ trait APIMethods400 {
|
||||
}
|
||||
tags <- Future(Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId))
|
||||
} yield {
|
||||
val json = JSONFactory.createTransactionTagsJSON(tags)
|
||||
val json = JSONFactory400.createAccountTagsJSON(tags)
|
||||
(json, HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
@ -1259,6 +1259,8 @@ trait APIMethods400 {
|
||||
|* 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
|
||||
|* Account Attributes - A list that might include custom defined account attribute
|
||||
|* Tags - A list of Tags assigned to this account
|
||||
|
|
||||
|This call returns the owner view and requires access to that view.
|
||||
|
|
||||
@ -1267,7 +1269,7 @@ trait APIMethods400 {
|
||||
|
|
||||
|""".stripMargin,
|
||||
emptyObjectJson,
|
||||
newModeratedCoreAccountJsonV400,
|
||||
moderatedCoreAccountJsonV400,
|
||||
List(BankAccountNotFound,UnknownError),
|
||||
Catalogs(Core, PSD2, notOBWG),
|
||||
apiTagAccount :: apiTagPSD2AIS :: apiTagNewStyle :: Nil)
|
||||
|
||||
@ -30,18 +30,17 @@ import java.util.Date
|
||||
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.APIUtil.{stringOptionOrNull, stringOrNull}
|
||||
import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON, createTransactionTagJSON}
|
||||
import code.api.v1_2_1.{BankRoutingJsonV121, TransactionTagJSON, UserJSONV121, ViewJSONV121}
|
||||
import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON}
|
||||
import code.api.v1_2_1.{BankRoutingJsonV121, JSONFactory, UserJSONV121, ViewJSONV121}
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140
|
||||
import code.api.v2_0_0.TransactionRequestChargeJsonV200
|
||||
import code.api.v3_0_0.JSONFactory300.createAccountRoutingsJSON
|
||||
import code.api.v3_0_0.{NewModeratedCoreAccountJsonV300, ViewBasicV300}
|
||||
import code.api.v3_0_0.ViewBasicV300
|
||||
import code.api.v3_1_0.AccountAttributeResponseJson
|
||||
import code.api.v3_1_0.JSONFactory310.createAccountAttributeJson
|
||||
import code.model.ModeratedBankAccount
|
||||
import code.transactionrequests.TransactionRequests.TransactionChallengeTypes
|
||||
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.ACCOUNT_OTP
|
||||
import com.openbankproject.commons.model.{AccountAttribute, AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, TransactionRequest, TransactionRequestBodyAllTypes, TransactionTag, View}
|
||||
import com.openbankproject.commons.model._
|
||||
|
||||
import scala.collection.immutable.List
|
||||
|
||||
@ -114,7 +113,7 @@ case class ModeratedCoreAccountJsonV400(
|
||||
account_routings: List[AccountRoutingJsonV121],
|
||||
views_basic: List[ViewBasicV300],
|
||||
account_attributes: List[AccountAttributeResponseJson],
|
||||
tags: List[TransactionTagJSON]
|
||||
tags: List[AccountTagJSON]
|
||||
)
|
||||
|
||||
case class ModeratedAccountJSON400(
|
||||
@ -128,9 +127,22 @@ case class ModeratedAccountJSON400(
|
||||
bank_id : String,
|
||||
account_routing :AccountRoutingJsonV121,
|
||||
account_attributes: List[AccountAttributeResponseJson],
|
||||
tags: List[TransactionTagJSON]
|
||||
tags: List[AccountTagJSON]
|
||||
)
|
||||
|
||||
case class AccountTagJSON(
|
||||
id : String,
|
||||
value : String,
|
||||
date : Date,
|
||||
user : UserJSONV121
|
||||
)
|
||||
|
||||
case class AccountTagsJSON(
|
||||
tags: List[AccountTagJSON]
|
||||
)
|
||||
case class PostAccountTagJSON(
|
||||
value : String
|
||||
)
|
||||
object JSONFactory400 {
|
||||
def createBankJSON400(bank: Bank): BankJson400 = {
|
||||
val obp = BankRoutingJsonV121("OBP", bank.bankId.value)
|
||||
@ -227,7 +239,7 @@ object JSONFactory400 {
|
||||
createAccountRoutingsJSON(account.accountRoutings),
|
||||
views_basic = availableViews.map(view => code.api.v3_0_0.ViewBasicV300(id = view.viewId.value, short_name = view.name, description = view.description, is_public = view.isPublic)),
|
||||
accountAttributes.map(createAccountAttributeJson),
|
||||
tags.map(createTransactionTagJSON)
|
||||
tags.map(createAccountTagJSON)
|
||||
)
|
||||
}
|
||||
|
||||
@ -248,7 +260,20 @@ object JSONFactory400 {
|
||||
stringOrNull(account.bankId.value),
|
||||
AccountRoutingJsonV121(stringOptionOrNull(account.accountRoutingScheme),stringOptionOrNull(account.accountRoutingAddress)),
|
||||
accountAttributes.map(createAccountAttributeJson),
|
||||
tags.map(createTransactionTagJSON)
|
||||
tags.map(createAccountTagJSON)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def createAccountTagsJSON(tags : List[TransactionTag]) : AccountTagsJSON = {
|
||||
new AccountTagsJSON(tags.map(createAccountTagJSON))
|
||||
}
|
||||
def createAccountTagJSON(tag : TransactionTag) : AccountTagJSON = {
|
||||
new AccountTagJSON(
|
||||
id = tag.id_,
|
||||
value = tag.value,
|
||||
date = tag.datePosted,
|
||||
user = JSONFactory.createUserJSON(tag.postedBy)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,19 @@ trait ConsumersProvider {
|
||||
def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
|
||||
def updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
|
||||
def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]]
|
||||
def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
|
||||
def getOrCreateConsumer(consumerId: Option[String],
|
||||
key: Option[String],
|
||||
secret: Option[String],
|
||||
azp: Option[String],
|
||||
iss: Option[String],
|
||||
sub: Option[String],
|
||||
isActive: Option[Boolean],
|
||||
name: Option[String],
|
||||
appType: Option[AppType],
|
||||
description: Option[String],
|
||||
developerEmail: Option[String],
|
||||
redirectURL: Option[String],
|
||||
createdByUserId: Option[String]): Box[Consumer]
|
||||
def populateMissingUUIDs(): Boolean
|
||||
}
|
||||
|
||||
@ -50,7 +62,19 @@ class RemotedataConsumersCaseClasses {
|
||||
case class createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
|
||||
case class updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
|
||||
case class updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String])
|
||||
case class getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
|
||||
case class getOrCreateConsumer(consumerId: Option[String],
|
||||
key: Option[String],
|
||||
secret: Option[String],
|
||||
azp: Option[String],
|
||||
iss: Option[String],
|
||||
sub: Option[String],
|
||||
isActive: Option[Boolean],
|
||||
name: Option[String],
|
||||
appType: Option[AppType],
|
||||
description: Option[String],
|
||||
developerEmail: Option[String],
|
||||
redirectURL: Option[String],
|
||||
createdByUserId: Option[String])
|
||||
case class populateMissingUUIDs()
|
||||
}
|
||||
|
||||
|
||||
@ -280,6 +280,9 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
|
||||
override def getOrCreateConsumer(consumerId: Option[String],
|
||||
key: Option[String],
|
||||
secret: Option[String],
|
||||
azp: Option[String],
|
||||
iss: Option[String],
|
||||
sub: Option[String],
|
||||
isActive: Option[Boolean],
|
||||
name: Option[String],
|
||||
appType: Option[AppType],
|
||||
@ -288,7 +291,13 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
|
||||
redirectURL: Option[String],
|
||||
createdByUserId: Option[String]): Box[Consumer] = {
|
||||
|
||||
Consumer.find(By(Consumer.consumerId, consumerId.getOrElse(Helpers.randomString(40)))) match {
|
||||
val consumer =
|
||||
// 1st try represent GatewayLogin usage of this function
|
||||
Consumer.find(By(Consumer.consumerId, consumerId.getOrElse("None"))) or {
|
||||
// 2nd try represent OAuth2 usage of this function
|
||||
Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.sub, sub.getOrElse("None")))
|
||||
}
|
||||
consumer match {
|
||||
case Full(c) => Full(c)
|
||||
case Failure(msg, t, c) => Failure(msg, t, c)
|
||||
case ParamFailure(x,y,z,q) => ParamFailure(x,y,z,q)
|
||||
@ -303,6 +312,18 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
|
||||
case Some(v) => c.secret(v)
|
||||
case None =>
|
||||
}
|
||||
azp match {
|
||||
case Some(v) => c.azp(v)
|
||||
case None =>
|
||||
}
|
||||
iss match {
|
||||
case Some(v) => c.iss(v)
|
||||
case None =>
|
||||
}
|
||||
sub match {
|
||||
case Some(v) => c.sub(v)
|
||||
case None =>
|
||||
}
|
||||
isActive match {
|
||||
case Some(v) => c.isActive(v)
|
||||
case None =>
|
||||
@ -407,6 +428,15 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{
|
||||
|
||||
object key extends MappedString(this, 250)
|
||||
object secret extends MappedString(this, 250)
|
||||
object azp extends MappedString(this, 250) {
|
||||
override def defaultValue = null
|
||||
}
|
||||
object iss extends MappedString(this, 250) {
|
||||
override def defaultValue = null
|
||||
}
|
||||
object sub extends MappedString(this, 250) {
|
||||
override def defaultValue = null
|
||||
}
|
||||
object isActive extends MappedBoolean(this){
|
||||
override def defaultValue = APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false)
|
||||
}
|
||||
@ -465,7 +495,7 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{
|
||||
*/
|
||||
object Consumer extends Consumer with MdcLoggable with LongKeyedMetaMapper[Consumer] with CRUDify[Long, Consumer]{
|
||||
|
||||
override def dbIndexes = UniqueIndex(key) :: super.dbIndexes
|
||||
override def dbIndexes = UniqueIndex(key) :: UniqueIndex(azp, sub) :: super.dbIndexes
|
||||
|
||||
//list all path : /admin/consumer/list
|
||||
override def calcPrefix = List("admin",_dbTableNameLC)
|
||||
|
||||
@ -54,8 +54,20 @@ object RemotedataConsumers extends ObpActorInit with ConsumersProvider {
|
||||
def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]] =
|
||||
(actor ? cc.updateConsumerCallLimits(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth)).mapTo[Box[Consumer]]
|
||||
|
||||
def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture(
|
||||
(actor ? cc.getOrCreateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]]
|
||||
def getOrCreateConsumer(consumerId: Option[String],
|
||||
key: Option[String],
|
||||
secret: Option[String],
|
||||
azp: Option[String],
|
||||
iss: Option[String],
|
||||
sub: Option[String],
|
||||
isActive: Option[Boolean],
|
||||
name: Option[String],
|
||||
appType: Option[AppType],
|
||||
description: Option[String],
|
||||
developerEmail: Option[String],
|
||||
redirectURL: Option[String],
|
||||
createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture(
|
||||
(actor ? cc.getOrCreateConsumer(consumerId, key, secret, azp, iss, sub, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]]
|
||||
)
|
||||
def populateMissingUUIDs(): Boolean = getValueFromFuture(
|
||||
(actor ? cc.populateMissingUUIDs()).mapTo[Boolean]
|
||||
|
||||
@ -53,9 +53,9 @@ class RemotedataConsumersActor extends Actor with ObpActorHelper with MdcLoggabl
|
||||
logger.debug("updateConsumerCallLimits(" + id + ", " + perSecond.getOrElse("None")+ ", " + perMinute.getOrElse("None") + ", " + perHour.getOrElse("None") + ", " + perDay.getOrElse("None") + ", " + perWeek.getOrElse("None") + ", " + perMonth.getOrElse("None") + ")")
|
||||
sender ! (mapper.updateConsumerCallLimitsRemote(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth))
|
||||
|
||||
case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) =>
|
||||
logger.debug("getOrCreateConsumer(" + consumerId.getOrElse("None") + ", " + "*****" + ", " + "*****" + ", " + isActive.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")
|
||||
sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
|
||||
case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], iss: Option[String], sub: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) =>
|
||||
logger.debug("getOrCreateConsumer(" + consumerId.getOrElse("None") + ", " + "*****" + ", " + "*****" + ", " + azp.getOrElse("None") + ", " + iss.getOrElse("None") + ", " + sub.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")
|
||||
sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, azp, iss, sub, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
|
||||
|
||||
case cc.populateMissingUUIDs() =>
|
||||
logger.debug("populateMissingUUIDs()")
|
||||
|
||||
@ -43,6 +43,20 @@ class WebUI extends MdcLoggable{
|
||||
|
||||
@transient protected val log = logger //Logger(this.getClass)
|
||||
|
||||
/**
|
||||
* This function transform GitHub markdown to html.
|
||||
* In case text contains html tag we avoid conversion.
|
||||
* @param text markdown/html
|
||||
* @return html code
|
||||
*/
|
||||
def makeHtml(text: String) = {
|
||||
val hasHtmlTag = """<[^>]*>""".r.findFirstIn(text).isDefined
|
||||
hasHtmlTag match {
|
||||
case false => PegdownOptions.convertGitHubDocMarkdownToHtml(text)
|
||||
case true => text
|
||||
}
|
||||
}
|
||||
|
||||
// Cookie Consent button.
|
||||
// Note we don't currently (7th Jan 2017) need to display the cookie consent message due to our limited use of cookies
|
||||
// If a deployment does make more use of cookies we would need to add a No button and we might want to make use of the
|
||||
|
||||
@ -5,7 +5,6 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiVersion
|
||||
import code.api.util.ErrorMessages.UserNotLoggedIn
|
||||
import code.api.v1_2_1.{TransactionTagJSON, TransactionTagsJSON}
|
||||
import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import net.liftweb.json.Serialization.write
|
||||
@ -24,7 +23,7 @@ class AccountTagTest extends V400ServerSetup {
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.deleteTagForViewOnAccount))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.getTagsForViewOnAccount))
|
||||
|
||||
lazy val accountTag = SwaggerDefinitionsJSON.transactionTagJSON
|
||||
lazy val accountTag = SwaggerDefinitionsJSON.accountTagJSON
|
||||
lazy val bankId = randomBankId
|
||||
lazy val bankAccount = randomPrivateAccount(bankId)
|
||||
lazy val view = randomOwnerViewPermalink(bankId, bankAccount)
|
||||
@ -71,12 +70,12 @@ class AccountTagTest extends V400ServerSetup {
|
||||
|
||||
Then("We should get a 201 and check the response body")
|
||||
response.code should equal(201)
|
||||
response.body.extract[TransactionTagJSON]
|
||||
response.body.extract[AccountTagJSON]
|
||||
|
||||
val requestGet = (v4_0_0_Request / "banks" / bankId / "accounts" / bankAccount.id / view / "metadata" / "tags").GET <@ (user1)
|
||||
val responseGet = makeGetRequest(requestGet)
|
||||
responseGet.code should equal(200)
|
||||
val tags = responseGet.body.extract[TransactionTagsJSON].tags
|
||||
val tags = responseGet.body.extract[AccountTagsJSON].tags
|
||||
tags.exists(_.value == accountTag.value) equals true
|
||||
val tagId = tags.map(_.id).headOption.getOrElse("")
|
||||
|
||||
|
||||
@ -164,8 +164,8 @@ case class UpdateViewJSON(
|
||||
* @define canEditOwnerComment If true, the view can edit the Transaction Owner Comment
|
||||
* @define canAddComment If true, the view can add a Transaction Comment
|
||||
* @define canDeleteComment If true, the view can delete a Transaction Comment
|
||||
* @define canAddTag If true, the view can add a Transaction Tag
|
||||
* @define canDeleteTag If true, the view can delete a Transaction Tag
|
||||
* @define canAddTag If true, the view can add a Transaction/Account Tag
|
||||
* @define canDeleteTag If true, the view can delete a Transaction/Account Tag
|
||||
* @define canAddImage If true, the view can add a Transaction Image
|
||||
* @define canDeleteImage If true, the view can delete a Transaction Image
|
||||
* @define canAddWhereTag If true, the view can add a Transaction Where Tag
|
||||
|
||||
Loading…
Reference in New Issue
Block a user