Merge pull request #2150 from constantine2nd/develop

Docs; Metrics
This commit is contained in:
Simon Redfern 2022-12-08 13:13:14 +01:00 committed by GitHub
commit a43d58a2c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 514 additions and 86 deletions

View File

@ -114,7 +114,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.4.1</version>
<version>42.4.3</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>

View File

@ -1204,4 +1204,11 @@ user_account_validated_redirect_url =
# Defines is it user is automatically validated, without SCA flow, after user account created
# In case is not defined default value is false
user_account_is_validated = false
user_account_is_validated = false
# Defines the number of days we keep rows in the table "MetricsArchive"
# default value is 3 years
retain_archive_metrics_days = 1095
# Defines the number of days we keep rows in the table "Metric" former "MappedMetric"
retain_metrics_days = 60

View File

@ -84,7 +84,7 @@ import code.metadata.tags.MappedTag
import code.metadata.transactionimages.MappedTransactionImage
import code.metadata.wheretags.MappedWhereTag
import code.methodrouting.MethodRouting
import code.metrics.{MappedConnectorMetric, MappedMetric}
import code.metrics.{MappedConnectorMetric, MappedMetric, MetricsArchive}
import code.migration.MigrationScriptLog
import code.model.{Consumer, _}
import code.model.dataAccess._
@ -96,7 +96,7 @@ import code.productcollectionitem.MappedProductCollectionItem
import code.products.MappedProduct
import code.ratelimiting.RateLimiting
import code.remotedata.RemotedataActors
import code.scheduler.DatabaseDriverScheduler
import code.scheduler.{DatabaseDriverScheduler, MetricsArchiveScheduler}
import code.scope.{MappedScope, MappedUserScope}
import code.apicollectionendpoint.ApiCollectionEndpoint
import code.apicollection.ApiCollection
@ -683,6 +683,7 @@ class Boot extends MdcLoggable {
case Full(i) => DatabaseDriverScheduler.start(i)
case _ => // Do not start it
}
MetricsArchiveScheduler.start(intervalInSeconds = 86400)
APIUtil.akkaSanityCheck() match {
@ -926,6 +927,8 @@ class Boot extends MdcLoggable {
object ToSchemify {
// The following tables will be accessed via Akka to the OBP Storage instance which in turn uses Mapper / JDBC
// TODO EPIC The aim is to have all models prefixed with "Mapped" but table names should not be prefixed with "Mapped
// TODO EPIC The aim is to remove all field name prefixes("m")
val modelsRemotedata: List[MetaMapper[_]] = List(
AccountAccess,
ViewDefinition,
@ -951,6 +954,7 @@ object ToSchemify {
MappedTransactionRequest,
TransactionRequestAttribute,
MappedMetric,
MetricsArchive,
MapperAccountHolders,
MappedEntitlement,
MappedConnectorMetric,

View File

@ -204,7 +204,7 @@ object DirectLogin extends RestHelper with MdcLoggable {
case "password" =>
basicPasswordValidation(parameterValue)
case "consumer_key" =>
checkMediumAlphaNumeric(parameterValue)
basicConsumerKeyValidation(parameterValue)
case "token" =>
checkMediumString(parameterValue)
case _ => ErrorMessages.InvalidDirectLoginParameters

View File

@ -740,13 +740,13 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
}
/** only A-Z, a-z, 0-9 and max length <= 512 */
def checkMediumAlphaNumeric(value:String): String ={
def basicConsumerKeyValidation(value:String): String ={
val valueLength = value.length
val regex = """^([A-Za-z0-9]+)$""".r
value match {
case regex(e) if(valueLength <= 512) => SILENCE_IS_GOLDEN
case regex(e) if(valueLength > 512) => ErrorMessages.InvalidValueLength
case _ => ErrorMessages.InvalidValueCharacters
case regex(e) if(valueLength > 512) => ErrorMessages.ConsumerKeyIsToLong
case _ => ErrorMessages.ConsumerKeyIsInvalid
}
}

View File

@ -500,6 +500,8 @@ object ErrorMessages {
val ConsentUserAuthContextCannotBeAdded = "OBP-35027: The Consent's User Auth Context cannot be added."
val ConsentRequestNotFound = "OBP-35028: Consent Request not found by CONSENT_REQUEST_ID. "
val ConsentRequestIsInvalid = "OBP-35029: The CONSENT_REQUEST_ID is invalid. "
val ConsumerKeyIsInvalid = "OBP-35030: The Consumer Key must be alphanumeric. (A-Z, a-z, 0-9)"
val ConsumerKeyIsToLong = "OBP-35031: The Consumer Key max length <= 512"
//Authorisations
val AuthorisationNotFound = "OBP-36001: Authorisation not found. Please specify valid values for PAYMENT_ID and AUTHORISATION_ID. "

View File

@ -807,6 +807,148 @@ object Glossary extends MdcLoggable {
"""
|Link Users and Customers in a many to many relationship. A User can represent many Customers (e.g. the bank may have several Customer records for the same individual or a dependant). In this way Customers can easily be attached / detached from Users.
""")
glossaryItems += GlossaryItem(
title = "Consent",
description =
s"""Consents provide a mechanism by which a third party App or User can access resources on behalf of a User.
|${getGlossaryItem("Consent OBP Flow Example")}
|${getGlossaryItem("Consent / Account Onboarding")}
|<img width="468" alt="OBP Access Control Image" src="$getServerUrl/media/images/glossary/OBP_Consent_Request__3_.png"></img>
|""".stripMargin)
glossaryItems += GlossaryItem(
title = "Consent OBP Flow Example",
description =
s"""
|#### 1) Call endpoint Create Consent Request using application access (Client Credentials)
|
|Url: [$getObpApiRoot/v5.0.0/consumer/consent-requests]($getObpApiRoot/v5.0.0/consumer/consent-requests)
|
|Post body:
|
|```
|{
| "everything": false,
| "account_access": [
|
| ],
| "entitlements": [
| {
| "bank_id": "gh.29.uk.x",
| "role_name": "CanGetCustomer"
| }
| ],
| "email": "marko@tesobe.com"
|}
|```
|
|Output:
|```
|{
| "consent_request_id":"bc0209bd-bdbe-4329-b953-d92d17d733f4",
| "payload":{
| "everything":false,
| "account_access":[],
| "entitlements":[{
| "bank_id":"gh.29.uk.x",
| "role_name":"CanGetCustomer"
| }],
| "email":"marko@tesobe.com"
| },
| "consumer_id":"0b34068b-cb22-489a-b1ee-9f49347b3346"
|}
|```
|
|
|
|
|#### 2) Call endpoint Create Consent By CONSENT_REQUEST_ID (SMS) with logged on user
|
|Url: $getObpApiRoot/v5.0.0/consumer/consent-requests/bc0209bd-bdbe-4329-b953-d92d17d733f4/EMAIL/consents
|
|Output:
|```
|{
| "consent_id":"155f86b2-247f-4702-a7b2-671f2c3303b6",
| "jwt":"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEN1c3RvbWVyIiwiYmFua19pZCI6ImdoLjI5LnVrLngifV0sImNyZWF0ZWRCeVVzZXJJZCI6ImFiNjUzOWE5LWIxMDUtNDQ4OS1hODgzLTBhZDhkNmM2MTY1NyIsInN1YiI6IjU3NGY4OGU5LTE5NDktNDQwNy05NTMwLTA0MzM3MTU5YzU2NiIsImF1ZCI6IjFhMTA0NjNiLTc4NTYtNDU4ZC1hZGI2LTViNTk1OGY1NmIxZiIsIm5iZiI6MTY2OTg5NDU5OSwiaXNzIjoiaHR0cDpcL1wvMTI3LjAuMC4xOjgwODAiLCJleHAiOjE2Njk4OTgxOTksImlhdCI6MTY2OTg5NDU5OSwianRpIjoiMTU1Zjg2YjItMjQ3Zi00NzAyLWE3YjItNjcxZjJjMzMwM2I2Iiwidmlld3MiOltdfQ.lLbn9BtgKvgAcb07if12SaEyPAKgXOEmr6x3Y5pU-vE",
| "status":"INITIATED",
| "consent_request_id":"bc0209bd-bdbe-4329-b953-d92d17d733f4"
|}
|```
|
|#### 3) We receive the SCA message via SMS
|Your consent challenge : 29131491, Application: Any application
|
|
|
|
|#### 4) Call endpoint Answer Consent Challenge with logged on user
|Url: $getObpApiRoot/v5.0.0/banks/gh.29.uk.x/consents/155f86b2-247f-4702-a7b2-671f2c3303b6/challenge
|Post body:
|```
|{
| "answer": "29131491"
|}
|```
|Output:
|```
|{
| "consent_id":"155f86b2-247f-4702-a7b2-671f2c3303b6",
| "jwt":"eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEN1c3RvbWVyIiwiYmFua19pZCI6ImdoLjI5LnVrLngifV0sImNyZWF0ZWRCeVVzZXJJZCI6ImFiNjUzOWE5LWIxMDUtNDQ4OS1hODgzLTBhZDhkNmM2MTY1NyIsInN1YiI6IjU3NGY4OGU5LTE5NDktNDQwNy05NTMwLTA0MzM3MTU5YzU2NiIsImF1ZCI6IjFhMTA0NjNiLTc4NTYtNDU4ZC1hZGI2LTViNTk1OGY1NmIxZiIsIm5iZiI6MTY2OTg5NDU5OSwiaXNzIjoiaHR0cDpcL1wvMTI3LjAuMC4xOjgwODAiLCJleHAiOjE2Njk4OTgxOTksImlhdCI6MTY2OTg5NDU5OSwianRpIjoiMTU1Zjg2YjItMjQ3Zi00NzAyLWE3YjItNjcxZjJjMzMwM2I2Iiwidmlld3MiOltdfQ.lLbn9BtgKvgAcb07if12SaEyPAKgXOEmr6x3Y5pU-vE",
| "status":"ACCEPTED"
|}
|```
|
|
|
|
|#### 5) Call endpoint Get Customer by CUSTOMER_ID with Consent Header
|
|Url: $getObpApiRoot/v5.0.0/banks/gh.29.uk.x/customers/a9c8bea0-4f03-4762-8f27-4b463bb50a93
|
|Request Header:
|```
|Consent-JWT:eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEN1c3RvbWVyIiwiYmFua19pZCI6ImdoLjI5LnVrLngifV0sImNyZWF0ZWRCeVVzZXJJZCI6ImFiNjUzOWE5LWIxMDUtNDQ4OS1hODgzLTBhZDhkNmM2MTY1NyIsInN1YiI6IjU3NGY4OGU5LTE5NDktNDQwNy05NTMwLTA0MzM3MTU5YzU2NiIsImF1ZCI6IjFhMTA0NjNiLTc4NTYtNDU4ZC1hZGI2LTViNTk1OGY1NmIxZiIsIm5iZiI6MTY2OTg5NDU5OSwiaXNzIjoiaHR0cDpcL1wvMTI3LjAuMC4xOjgwODAiLCJleHAiOjE2Njk4OTgxOTksImlhdCI6MTY2OTg5NDU5OSwianRpIjoiMTU1Zjg2YjItMjQ3Zi00NzAyLWE3YjItNjcxZjJjMzMwM2I2Iiwidmlld3MiOltdfQ.lLbn9BtgKvgAcb07if12SaEyPAKgXOEmr6x3Y5pU-
|```
|Output:
|```
|{
| "bank_id":"gh.29.uk.x",
| "customer_id":"a9c8bea0-4f03-4762-8f27-4b463bb50a93",
| "customer_number":"0908977830011-#2",
| "legal_name":"NONE",
| "mobile_phone_number":"+3816319549071",
| "email":"marko@tesobe.com1",
| "face_image":{
| "url":"www.openbankproject",
| "date":"2017-09-18T22:00:00Z"
| },
| "date_of_birth":"2017-09-18T22:00:00Z",
| "relationship_status":"Single",
| "dependants":5,
| "dob_of_dependants":[],
| "credit_rating":{
| "rating":"3",
| "source":"OBP"
| },
| "credit_limit":{
| "currency":"EUR",
| "amount":"10001"
| },
| "highest_education_attained":"Bachelors Degree",
| "employment_status":"Employed",
| "kyc_status":true,
| "last_ok_date":"2017-09-18T22:00:00Z",
| "title":null,
| "branch_id":"3210",
| "name_suffix":null,
| "customer_attributes":[]
|}
|```
|""".stripMargin)
glossaryItems += GlossaryItem(

View File

@ -19,5 +19,8 @@ object SecureRandomUtil {
def alphanumeric(nrChars: Int = 24): String = {
new BigInteger(nrChars * 5, csprng).toString(32)
}
def numeric(maxNumber: Int = 99999999): String = {
csprng.nextInt(maxNumber).toString()
}
}

View File

@ -3515,7 +3515,7 @@ trait APIMethods310 {
challengeAnswer = Props.mode match {
case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
case _ => Random.nextInt(99999999).toString()
case _ => SecureRandomUtil.numeric()
}
createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None)) map {
i => connectorEmptyResponse(i, callContext)

View File

@ -591,7 +591,19 @@ trait APIMethods500 {
"POST",
"/consumer/consent-requests",
"Create Consent Request",
s"""""",
s"""
|Client Authentication (mandatory)
|
|It is used when applications request an access token to access their own resources, not on behalf of a user.
|
|The client needs to authenticate themselves for this request.
|In case of public client we use client_id and private kew to obtain access token, otherwise we use client_id and client_secret.
|The obtained access token is used in the HTTP Bearer auth header of our request.
|
|Example:
|Authorization: Bearer eXtneO-THbQtn3zvK_kQtXXfvOZyZFdBCItlPDbR2Bk.dOWqtXCtFX-tqGTVR0YrIjvAolPIVg7GZ-jz83y6nA0
|
|""".stripMargin,
postConsentRequestJsonV500,
consentRequestResponseJson,
List(
@ -729,10 +741,11 @@ trait APIMethods500 {
nameOf(createConsentByConsentRequestIdEmail),
"POST",
"/consumer/consent-requests/CONSENT_REQUEST_ID/EMAIL/consents",
"Create Consent By Request Id(EMAIL)",
"Create Consent By CONSENT_REQUEST_ID (EMAIL)",
s"""
|
|This endpoint starts the process of creating a Consent by consent request id.
|This endpoint finishes the process of creating a Consent by CONSENT_REQUEST_ID.
|Please note that the Consent cannot elevate the privileges logged in user already have.
|
|""",
EmptyBody,
@ -756,10 +769,11 @@ trait APIMethods500 {
nameOf(createConsentByConsentRequestIdSms),
"POST",
"/consumer/consent-requests/CONSENT_REQUEST_ID/SMS/consents",
"Create Consent By Request Id (SMS)",
"Create Consent By CONSENT_REQUEST_ID (SMS)",
s"""
|
|This endpoint starts the process of creating a Consent.
|This endpoint finishes the process of creating a Consent.
|Please note that the Consent cannot elevate the privileges logged in user already have.
|
|""",
EmptyBody,
@ -853,7 +867,7 @@ trait APIMethods500 {
challengeAnswer = Props.mode match {
case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
case _ => Random.nextInt(99999999).toString()
case _ => SecureRandomUtil.numeric()
}
createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, Some(consentRequestId))) map {
i => connectorEmptyResponse(i, callContext)

View File

@ -58,6 +58,21 @@ trait APIMetrics {
verb: String,
httpCode: Option[Int],
correlationId: String): Unit
def saveMetricsArchive(primaryKey: Long,
userId: String,
url: String,
date: Date,
duration: Long,
userName: String,
appName: String,
developerEmail: String,
consumerId: String,
implementedByPartialFunction: String,
implementedInVersion: String,
verb: String,
httpCode: Option[Int],
correlationId: String): Unit
// //TODO: ordering of list? should this be by date? currently not enforced
// def getAllGroupedByUrl() : Map[String, List[APIMetric]]
@ -82,6 +97,7 @@ trait APIMetrics {
class RemotedataMetricsCaseClasses {
case class saveMetric(userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String)
case class saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String)
// case class getAllGroupedByUrl()
// case class getAllGroupedByDay()
// case class getAllGroupedByUserId()
@ -96,6 +112,7 @@ object RemotedataMetricsCaseClasses extends RemotedataMetricsCaseClasses
trait APIMetric {
def getMetricId() : Long
def getUrl() : String
def getDate() : Date
def getDuration(): Long

View File

@ -19,6 +19,7 @@ object ElasticsearchMetrics extends APIMetrics {
es.indexMetric(userId, url, date, duration, userName, appName, developerEmail, correlationId)
}
}
override def saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String): Unit = ???
// override def getAllGroupedByUserId(): Map[String, List[APIMetric]] = {
// //TODO: replace the following with valid ES query

View File

@ -64,6 +64,29 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}
metric.save
}
override def saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String): Unit = {
val metric = MetricsArchive.find(By(MetricsArchive.id, primaryKey)).getOrElse(MetricsArchive.create)
metric
.metricId(primaryKey)
.userId(userId)
.url(url)
.date(date)
.duration(duration)
.userName(userName)
.appName(appName)
.developerEmail(developerEmail)
.consumerId(consumerId)
.implementedByPartialFunction(implementedByPartialFunction)
.implementedInVersion(implementedInVersion)
.verb(verb)
.correlationId(correlationId)
httpCode match {
case Some(code) => metric.httpCode(code)
case None =>
}
metric.save
}
private lazy val getDbConnectionParameters: (String, String, String) = {
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
@ -473,6 +496,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}
class MappedMetric extends APIMetric with LongKeyedMapper[MappedMetric] with IdPK {
override def getSingleton = MappedMetric
object userId extends UUIDString(this)
@ -492,9 +516,12 @@ class MappedMetric extends APIMetric with LongKeyedMapper[MappedMetric] with IdP
//(GET, POST etc.) --S.request.get.requestType
object verb extends MappedString(this, 16)
object httpCode extends MappedInt(this)
object correlationId extends MappedUUID(this)
object correlationId extends MappedUUID(this){
override def dbNotNull_? = true
}
override def getMetricId(): Long = id.get
override def getUrl(): String = url.get
override def getDate(): Date = date.get
override def getDuration(): Long = duration.get
@ -511,6 +538,59 @@ class MappedMetric extends APIMetric with LongKeyedMapper[MappedMetric] with IdP
}
object MappedMetric extends MappedMetric with LongKeyedMetaMapper[MappedMetric] {
//override def dbIndexes = Index(userId) :: Index(url) :: Index(date) :: Index(userName) :: Index(appName) :: Index(developerEmail) :: super.dbIndexes
// Please note that the old table name was "MappedMetric"
// Renaming implications:
// - at an existing sandbox the table "MappedMetric" still exists with rows until this change is deployed at it
// and new rows are stored in the table "Metric"
// - at a fresh sandbox there is no the table "MappedMetric", only "Metric" is present
override def dbTableName = "Metric" // define the DB table name
override def dbIndexes = Index(date) :: Index(consumerId) :: super.dbIndexes
}
class MetricsArchive extends APIMetric with LongKeyedMapper[MetricsArchive] with IdPK {
override def getSingleton = MetricsArchive
object metricId extends MappedLong(this)
object userId extends UUIDString(this)
object url extends MappedString(this, 2000) // TODO Introduce / use class for Mapped URLs
object date extends MappedDateTime(this)
object duration extends MappedLong(this)
object userName extends MappedString(this, 64) // TODO constrain source value length / truncate value on insert
object appName extends MappedString(this, 64) // TODO constrain source value length / truncate value on insert
object developerEmail extends MappedString(this, 64) // TODO constrain source value length / truncate value on insert
//The consumerId, Foreign key to Consumer not key
object consumerId extends UUIDString(this)
//name of the Scala Partial Function being used for the endpoint
object implementedByPartialFunction extends MappedString(this, 128)
//name of version where the call is implemented) -- S.request.get.view
object implementedInVersion extends MappedString(this, 16)
//(GET, POST etc.) --S.request.get.requestType
object verb extends MappedString(this, 16)
object httpCode extends MappedInt(this)
object correlationId extends MappedUUID(this){
override def dbNotNull_? = true
}
override def getMetricId(): Long = metricId.get
override def getUrl(): String = url.get
override def getDate(): Date = date.get
override def getDuration(): Long = duration.get
override def getUserId(): String = userId.get
override def getUserName(): String = userName.get
override def getAppName(): String = appName.get
override def getDeveloperEmail(): String = developerEmail.get
override def getConsumerId(): String = consumerId.get
override def getImplementedByPartialFunction(): String = implementedByPartialFunction.get
override def getImplementedInVersion(): String = implementedInVersion.get
override def getVerb(): String = verb.get
override def getHttpCode(): Int = httpCode.get
override def getCorrelationId(): String = correlationId.get
}
object MetricsArchive extends MetricsArchive with LongKeyedMetaMapper[MetricsArchive] {
override def dbIndexes =
Index(userId) :: Index(consumerId) :: Index(url) :: Index(date) :: Index(userName) ::
Index(appName) :: Index(developerEmail) :: super.dbIndexes
}

View File

@ -31,13 +31,13 @@ import java.util.Date
import code.api.util.OBPQueryParam
import net.liftweb.common.Box
import net.liftweb.mongodb.record.field.{DateField, ObjectIdPk}
import net.liftweb.mongodb.record.field.{DateField, LongPk}
import net.liftweb.mongodb.record.{MongoMetaRecord, MongoRecord}
import net.liftweb.record.field.{IntField, LongField, StringField}
import scala.concurrent.Future
private class MongoAPIMetric extends MongoRecord[MongoAPIMetric] with ObjectIdPk[MongoAPIMetric] with APIMetric {
private class MongoAPIMetric extends MongoRecord[MongoAPIMetric] with LongPk[MongoAPIMetric] with APIMetric {
def meta = MongoAPIMetric
object userId extends StringField(this,255)
object url extends StringField(this,255)
@ -58,6 +58,7 @@ import scala.concurrent.Future
object correlationId extends StringField(this,255)
def getMetricId(): Long = id.get
def getUrl() = url.get
def getDate() = date.get
def getDuration(): Long = duration.get
@ -91,6 +92,8 @@ private object MongoAPIMetric extends MongoAPIMetric with MongoMetaRecord[MongoA
correlationId(correlationId)
saveTheRecord()
}
override def saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String): Unit = ???
// def getAllGroupedByUrl() : Map[String, List[APIMetric]] = {
// MongoAPIMetric.findAll.groupBy[String](_.url.get)
@ -107,6 +110,7 @@ private object MongoAPIMetric extends MongoAPIMetric with MongoMetaRecord[MongoA
override def getAllMetrics(queryParams: List[OBPQueryParam]): List[APIMetric] = {
MongoAPIMetric.findAll
}
override def bulkDeleteMetrics(): Boolean = ???
override def getAllAggregateMetricsFuture(queryParams: List[OBPQueryParam]): Future[Box[List[AggregateMetrics]]] = ???

View File

@ -261,17 +261,20 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
}
val updatedConsumer = c.saveMe()
// In case we use Hydra ORY as Identity Provider we update corresponding client at Hydra side a well
if(integrateWithHydra && Option(originIsActive) != isActive && isActive.isDefined) {
val clientId = c.key.get
val existsOAuth2Client = Box.tryo(hydraAdmin.getOAuth2Client(clientId))
.filter(null !=)
// if disable consumer, delete hydra client, else if enable consumer, create hydra client
// note: hydra update client endpoint have bug, can't update any client, So here delete and create new one
// Please note:
// Hydra's update client endpoint has a bug. Cannot update clients, so we need to delete and create a new one.
// If a consumer is disabled we delete a corresponding client at Hydra side.
// If the consumer is enabled we delete and create our corresponding client at Hydra side.
if (isActive == Some(false)) {
existsOAuth2Client
.map { oAuth2Client =>
hydraAdmin.deleteOAuth2Client(clientId)
// set grantTypes to empty to disable the client
// set grantTypes to empty list in order to disable the client
oAuth2Client.setGrantTypes(Collections.emptyList())
hydraAdmin.createOAuth2Client(oAuth2Client)
}
@ -279,7 +282,7 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
existsOAuth2Client
.map { oAuth2Client =>
hydraAdmin.deleteOAuth2Client(clientId)
// set grantTypes to correct value to enable the client
// set grantTypes to correct value in order to enable the client
oAuth2Client.setGrantTypes(HydraUtil.grantTypes)
hydraAdmin.createOAuth2Client(oAuth2Client)
}
@ -437,6 +440,7 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
case None =>
}
val createdConsumer = c.saveMe()
// In case we use Hydra ORY as Identity Provider we create corresponding client at Hydra side a well
if(integrateWithHydra) createHydraClient(createdConsumer)
createdConsumer
}

View File

@ -322,6 +322,7 @@ class AuthUser extends MegaProtoUser[AuthUser] with CreatedUpdated with MdcLogga
override def displayName = S.?("provider")
override val fieldId = Some(Text("txtProvider"))
override def validations = validUri(this) _ :: super.validations
override def defaultValue: String = Constant.HostName
}

View File

@ -18,6 +18,10 @@ object RemotedataMetrics extends ObpActorInit with APIMetrics {
def saveMetric(userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String) : Unit = getValueFromFuture(
(actor ? cc.saveMetric(userId, url, date, duration, userName, appName, developerEmail, consumerId, implementedByPartialFunction, implementedInVersion, verb, httpCode, correlationId)).mapTo[Unit]
)
def saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String) : Unit = getValueFromFuture(
(actor ? cc.saveMetricsArchive(primaryKey, userId, url, date, duration, userName, appName, developerEmail, consumerId, implementedByPartialFunction, implementedInVersion, verb, httpCode, correlationId)).mapTo[Unit]
)
// def getAllGroupedByUrl() : Map[String, List[APIMetric]] =
// extractFuture(actor ? cc.getAllGroupedByUrl())

View File

@ -0,0 +1,102 @@
package code.scheduler
import java.util.concurrent.TimeUnit
import java.util.{Calendar, Date}
import code.actorsystem.ObpLookupSystem
import code.api.util.{APIUtil, OBPToDate}
import code.metrics.{APIMetric, APIMetrics, MappedMetric, MetricsArchive}
import code.util.Helper.MdcLoggable
import net.liftweb.common.Full
import net.liftweb.mapper.{By, By_<=}
import scala.concurrent.duration._
object MetricsArchiveScheduler extends MdcLoggable {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler
private val oneDayInMillis: Long = 86400000
def start(intervalInSeconds: Long): Unit = {
scheduler.schedule(
initialDelay = Duration(getMillisTillMidnight(), TimeUnit.MILLISECONDS),
interval = Duration(intervalInSeconds, TimeUnit.SECONDS),
runnable = new Runnable {
def run(): Unit = {
conditionalDeleteMetricsRow()
deleteOutdatedRowsFromMetricsArchive()
}
}
)
}
def deleteOutdatedRowsFromMetricsArchive() = {
val currentTime = new Date()
val defaultValue : Int = 365 * 3
val days = APIUtil.getPropsAsLongValue("retain_archive_metrics_days", defaultValue) match {
case days if days > 364 => days
case _ => 365
}
val someYearsAgo: Date = new Date(currentTime.getTime - (oneDayInMillis * days))
// Delete the outdated rows from the table "MetricsArchive"
MetricsArchive.bulkDelete_!!(By_<=(MetricsArchive.date, someYearsAgo))
}
def conditionalDeleteMetricsRow() = {
val currentTime = new Date()
val days = APIUtil.getPropsAsLongValue("retain_metrics_days", 60) match {
case days if days > 59 => days
case _ => 60
}
val someDaysAgo: Date = new Date(currentTime.getTime - (oneDayInMillis * days))
// Get the data from the table "Metric" older than specified by retain_metrics_days
val canditateMetricRowsToMove = APIMetrics.apiMetrics.vend.getAllMetrics(List(OBPToDate(someDaysAgo)))
canditateMetricRowsToMove map { i =>
// and copy it to the table "MetricsArchive"
copyRowToMetricsArchive(i)
}
val maybeDeletedRows: List[(Boolean, Long)] = canditateMetricRowsToMove map { i =>
// and delete it after successful coping
MetricsArchive.find(By(MetricsArchive.metricId, i.getMetricId())) match {
case Full(_) => (MappedMetric.bulkDelete_!!(By(MappedMetric.id, i.getMetricId())), i.getMetricId())
case _ => (false, i.getMetricId())
}
}
maybeDeletedRows.filter(_._1 == false).map { i =>
logger.warn(s"Row with primary key ${i._2} of the table Metric is not successfully copied.")
}
}
private def copyRowToMetricsArchive(i: APIMetric): Unit = {
APIMetrics.apiMetrics.vend.saveMetricsArchive(
i.getMetricId(),
i.getUserId(),
i.getUrl(),
i.getDate(),
i.getDuration(),
i.getUserName(),
i.getAppName(),
i.getDeveloperEmail(),
i.getConsumerId(),
i.getImplementedByPartialFunction(),
i.getImplementedInVersion(),
i.getVerb(),
Some(i.getHttpCode()),
i.getCorrelationId()
)
}
private def getMillisTillMidnight(): Long = {
val c = Calendar.getInstance
c.add(Calendar.DAY_OF_MONTH, 1)
c.set(Calendar.HOUR_OF_DAY, 0)
c.set(Calendar.MINUTE, 0)
c.set(Calendar.SECOND, 0)
c.set(Calendar.MILLISECOND, 0)
c.getTimeInMillis - System.currentTimeMillis
}
}

View File

@ -134,6 +134,7 @@ class ConsumerRegistration extends MdcLoggable {
val jwks = jwksVar.is
val jwsAlg = signingAlgVar.is
var jwkPrivateKey: String = s"Please change this value to ${if(StringUtils.isNotBlank(jwksUri)) "jwks_uri" else "jwks"} corresponding private key"
// In case we use Hydra ORY as Identity Provider we create corresponding client at Hydra side a well
if(HydraUtil.integrateWithHydra) {
HydraUtil.createHydraClient(consumer, oAuth2Client => {
val signingAlg = signingAlgVar.is

View File

@ -33,7 +33,7 @@ import java.io.InputStream
import code.api.Constant
import code.api.util.APIUtil.{activeBrand, getRemoteIpAddress, getServerUrl}
import code.api.util.ApiRole.CanReadGlossary
import code.api.util.{APIUtil, ApiRole, CustomJsonFormats, ErrorMessages, PegdownOptions}
import code.api.util.{APIUtil, ApiRole, CustomJsonFormats, ErrorMessages, I18NUtil, PegdownOptions}
import code.model.dataAccess.AuthUser
import code.util.Helper.MdcLoggable
import net.liftweb.http.{LiftRules, S, SessionVar}
@ -90,11 +90,14 @@ class WebUI extends MdcLoggable{
if (supportedLocales.contains(locale) || supportedLocales.contains(hyphenLocale) ) {""} else {"none"}
}
val page = Constant.HostName + S.uri
val language = I18NUtil.currentLocale().getLanguage()
"#es a [href]" #> scala.xml.Unparsed(s"${page}?${replaceLocale("locale=es_ES")}") &
"#en a [href]" #> scala.xml.Unparsed(s"${page}?${replaceLocale("locale=en_GB")}") &
"#es a [style]" #> s"display: ${displayLanguage("es_ES")}" &
"#locale_separator [style]" #> {if(supportedLocales.size == 1) "display: none" else ""} &
"#en a [style]" #> s"display: ${displayLanguage("en_GB")}"
"#en a [style]" #> s"display: ${displayLanguage("en_GB")}" &
s"#${language.toLowerCase()} *" #> scala.xml.Unparsed(s"<b>${language.toUpperCase()}</b>")
}

View File

@ -1,10 +1,13 @@
package deletion
import code.accountattribute.MappedAccountAttribute
import code.api.APIFailureNewStyle
import code.api.util.APIUtil.fullBoxOrException
import code.api.util.ErrorMessages.CouldNotDeleteCascade
import code.customer.CustomerX
import code.customeraccountlinks.CustomerAccountLink
import code.model.dataAccess.{MappedBank, MappedBankAccount}
import com.openbankproject.commons.model.{AccountId, BankId}
import com.openbankproject.commons.model.{BankId, CustomerId}
import deletion.DeletionUtil.databaseAtomicTask
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.db.DB
@ -14,8 +17,23 @@ import net.liftweb.util.DefaultConnectionIdentifier
object DeleteBankCascade {
def delete(bankId: BankId): Boolean = {
MappedBankAccount.findAll(By(MappedBankAccount.bank, bankId.value))
.forall(i => DeleteAccountCascade.delete(i.bankId, i.accountId)) && deleteBank(bankId)
MappedBankAccount.findAll(By(MappedBankAccount.bank, bankId.value)).forall { i =>
// Delete customer related to the account via account attribute "customer_number"
MappedAccountAttribute.findAll(
By(MappedAccountAttribute.mBankIdId, bankId.value)
).filter(_.name == "customer_number").foreach { i =>
val customerNumber = i.value
CustomerX.customerProvider.vend.getCustomerByCustomerNumber(customerNumber, bankId).map( i =>
DeleteCustomerCascade.delete(CustomerId(i.customerId))
)
}
// Delete customer related to the account
CustomerAccountLink.findAll(By(CustomerAccountLink.AccountId, i.accountId.value)).forall(i =>
DeleteCustomerCascade.delete(CustomerId(i.customerId))
)
// Delete account
DeleteAccountCascade.delete(i.bankId, i.accountId)
} && deleteBank(bankId)
}
def atomicDelete(bankId: BankId): Box[Boolean] = databaseAtomicTask {

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -1,6 +1,5 @@
package code.api
import code.api.util.APIUtil.OAuth.Token
import code.api.util.ErrorMessages
import code.api.util.ErrorMessages._
import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
@ -8,7 +7,6 @@ import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0
import code.api.v3_0_0.UserJsonV300
import code.consumer.Consumers
import code.loginattempts.LoginAttempt
import code.model
import code.model.dataAccess.AuthUser
import code.setup.{APIResponse, ServerSetup}
import code.userlocks.UserLocksProvider

View File

@ -432,7 +432,7 @@ class AccountTest extends V400ServerSetup {
scenario(s"We will test ${ApiEndpoint7.name}", ApiEndpoint7, VersionOfApi) {
// Create customer
val bankId = randomBankId
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
// Link Customer to a User
val postJson = SwaggerDefinitionsJSON.createUserCustomerLinkJson

View File

@ -25,7 +25,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
lazy val bankId = randomBankId
feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "correlated-users").GET
@ -36,7 +36,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
}
}
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access without roles") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "correlated-users").GET <@(user1)
@ -51,7 +51,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access with roles") {
scenario("We will call the endpoint without user credentials-bank level role", ApiEndpoint1, VersionOfApi) {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val link = createUserCustomerLink(bankId, resourceUser1.userId, customerId)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanGetCorrelatedUsersInfo.toString)
@ -66,7 +66,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
}
scenario("We will call the endpoint without user credentials - system level role", ApiEndpoint1, VersionOfApi) {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val link = createUserCustomerLink(bankId, resourceUser1.userId, customerId)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetCorrelatedUsersInfoAtAnyBank.toString)
@ -83,7 +83,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
feature(s"test $ApiEndpoint2 version $VersionOfApi - Unauthorized access") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "my" / "correlated-entities").GET
@ -95,7 +95,7 @@ class CorrelatedUserInfoTest extends V400ServerSetup {
}
feature(s"test $ApiEndpoint2 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials-bank level role", ApiEndpoint1, VersionOfApi) {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val link = createUserCustomerLink(bankId, resourceUser1.userId, customerId)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanGetCorrelatedUsersInfo.toString)

View File

@ -40,7 +40,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST
@ -56,7 +56,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
@ -73,7 +73,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
val response400 = makePostRequest(request400, write(putCustomerAttributeJsonV400))
@ -97,7 +97,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
val response400 = makePostRequest(request400, write(putCustomerAttributeJsonV400))
@ -122,7 +122,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attributes" / "customerAttributeId").PUT
@ -138,7 +138,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attributes" / "customerAttributeId").PUT <@ (user1)
@ -154,7 +154,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
@ -180,7 +180,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attributes" / "customerAttributeId").PUT <@ (user1)
@ -206,7 +206,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("We grant the role to the user1")
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, canUpdateCustomerAttributeAtOneBank.toString)
@ -226,7 +226,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("We grant the role to the user1")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canUpdateCustomerAttributeAtAnyBank.toString)
@ -248,7 +248,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
When("We make a request v4.0.0")
Then("we create the Customer Attribute ")
@ -276,7 +276,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId:String, customerId:String, user1)
@ -296,7 +296,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId:String, customerId:String, user1)
@ -317,7 +317,7 @@ class CustomerAttributesTest extends V400ServerSetup {
val bankId = randomBankId
val postCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
createAndGetCustomerAttributeIdViaEndpoint(bankId:String, customerId:String, user1)
@ -341,7 +341,7 @@ class CustomerAttributesTest extends V400ServerSetup {
scenario("We will call the endpoint with user credentials", ApiEndpoint5, VersionOfApi) {
val bankId = randomBankId
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -406,7 +406,7 @@ class CustomerAttributesTest extends V400ServerSetup {
When("We create an attribute for later deletion")
val bankId = randomBankId
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val requestCreation = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, canCreateCustomerAttributeAtOneBank.toString)
@ -443,7 +443,7 @@ class CustomerAttributesTest extends V400ServerSetup {
When("We create an attribute for later deletion - canDeleteCustomerAttributeAtAnyBank")
val bankId = randomBankId
val putCustomerAttributeJsonV400 = SwaggerDefinitionsJSON.customerAttributeJsonV400.copy(name="test")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
val requestCreation = (v4_0_0_Request / "banks" / bankId / "customers" / customerId / "attribute").POST <@ (user1)
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, canCreateCustomerAttributeAtOneBank.toString)

View File

@ -1,24 +1,22 @@
package code.api.v4_0_0
import java.util.concurrent.TimeUnit
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createViewJsonV300
import code.api.util.APIUtil.OAuth._
import code.api.util.{APIUtil, ApiRole}
import code.api.util.ApiRole.{CanDeleteAccountCascade, CanDeleteBankCascade}
import code.api.util.ApiRole.{CanDeleteBankCascade, canGetCustomersMinimalAtAnyBank}
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
import code.api.util.{APIUtil, ApiRole}
import code.api.v3_1_0.CreateAccountResponseJsonV310
import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
import code.entitlement.Entitlement
import code.model.dataAccess.MappedBank
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage}
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.Serialization.write
import net.liftweb.mapper.By
import org.scalatest.Tag
import java.util.concurrent.TimeUnit
class DeleteBankCascadeTest extends V400ServerSetup {
/**
@ -88,6 +86,16 @@ class DeleteBankCascadeTest extends V400ServerSetup {
Some("LKJL98769F")
)
val customerNumber = createCustomerViaEndpointAndGetNumber(bankId, resourceUser1.userId)
createAccountAttributeViaEndpoint(
bankId,
account.account_id,
"customer_number",
customerNumber,
"STRING",
None
)
grantUserAccessToViewViaEndpoint(
bankId,
account.account_id,
@ -113,6 +121,16 @@ class DeleteBankCascadeTest extends V400ServerSetup {
When("We try to delete one more time")
makeDeleteRequest(request400).code should equal(404)
// Bnam customers must be deleted as well
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canGetCustomersMinimalAtAnyBank.toString)
When(s"We make a request $VersionOfApi")
val request = (v4_0_0_Request / "customers-minimal").GET <@(user1)
val response = makeGetRequest(request)
Then("We should get a 200")
response.code should equal(200)
val responseBody = response.body.extract[CustomersMinimalJsonV400]
responseBody.customers.length equals 0
}
}

View File

@ -53,7 +53,7 @@ class DeleteCustomerCascadeTest extends V400ServerSetup {
}
feature(s"test $ApiEndpoint1 - Authorized access") {
scenario("We will call the endpoint with user credentials", ApiEndpoint1, VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute")
createAndGetCustomerAttributeIdViaEndpoint(bankId:String, customerId:String, user1)

View File

@ -73,7 +73,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
}
scenario("We will call the endpoint without user credentials", ApiEndpoint2, VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -291,7 +291,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
//////// auto validate endpoint
feature(s"test Force-Error header $VersionOfApi - auto validate static endpoint, authenticated access") {
scenario(s"We will call the endpoint $ApiEndpoint2 with Force-Error have wrong format header", VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -310,7 +310,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
}
scenario(s"We will call the endpoint $ApiEndpoint2 with Force-Error header value not support by current endpoint", VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -328,7 +328,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
}
scenario(s"We will call the endpoint $ApiEndpoint2 with Response-Code header value is not Int", VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -346,7 +346,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
}
scenario(s"We will call the endpoint $ApiEndpoint2 with correct Force-Error header value", VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -366,7 +366,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
}
scenario(s"We will call the endpoint $ApiEndpoint2 with correct Force-Error header value and Response-Code value", VersionOfApi) {
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)
@ -387,7 +387,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
scenario(s"We will call the endpoint $ApiEndpoint2 with correct Force-Error header value, but 'enable.force_error=false'", VersionOfApi) {
setPropsValues("enable.force_error"->"false")
val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
Then("we create the Customer Attribute ")
val customerAttributeId = createAndGetCustomerAttributeIdViaEndpoint(bankId: String, customerId: String, user1)

View File

@ -137,7 +137,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
other_account_secondary_routing_address= counterpartyCounterparty.otherAccountSecondaryRoutingAddress
), bodyValue, description, sharedChargePolicy)
val customerId = createAndGetCustomerIdViaEndpoint(bankId.value, user1)
val customerId = createAndGetCustomerIdViaEndpoint(bankId.value, resourceUser1.userId)
val requestWithAuthUser = (v5_0_0_Request / "management" /"banks" / bankId.value / "cards" ).POST <@ (user1)
val properCardJson = createPhysicalCardJsonV500.copy(
account_id = fromAccount.accountId.value,

View File

@ -56,7 +56,7 @@ class UserCustomerLinkTest extends V400ServerSetup {
}
feature(s"test $ApiEndpoint3 version $VersionOfApi - Unauthorized access") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "user_customer_links" / "customers" / customerId ).GET
@ -67,7 +67,7 @@ class UserCustomerLinkTest extends V400ServerSetup {
}
}
feature(s"test $ApiEndpoint3 version $VersionOfApi - Authorized access") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v4.0.0")
val request400 = (v4_0_0_Request / "banks" / bankId / "user_customer_links" / "customers" / customerId).GET <@(user1)
@ -107,7 +107,7 @@ class UserCustomerLinkTest extends V400ServerSetup {
feature(s"test $ApiEndpoint4 version $VersionOfApi - Unauthorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint2, VersionOfApi) {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
lazy val postJson = SwaggerDefinitionsJSON.createUserCustomerLinkJson
.copy(user_id = firstUserId, customer_id = customerId)
When("We make a request v4.0.0")
@ -120,7 +120,7 @@ class UserCustomerLinkTest extends V400ServerSetup {
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access") {
scenario("We will call the endpoint without user credentials", ApiEndpoint2, VersionOfApi) {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
lazy val postJson = SwaggerDefinitionsJSON.createUserCustomerLinkJson
.copy(user_id = firstUserId, customer_id = customerId)
When("We make a request v4.0.0")
@ -133,7 +133,7 @@ class UserCustomerLinkTest extends V400ServerSetup {
}
}
feature(s"test $ApiEndpoint1, $ApiEndpoint2, $ApiEndpoint4 version $VersionOfApi - All good") {
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, user1)
lazy val customerId = createAndGetCustomerIdViaEndpoint(bankId, resourceUser1.userId)
lazy val postJson = SwaggerDefinitionsJSON.createUserCustomerLinkJson
.copy(user_id = firstUserId, customer_id = customerId)

View File

@ -183,19 +183,24 @@ trait V400ServerSetup extends ServerSetupWithTestData with DefaultUsers {
responseCreate310.body.extract[AccountAttributeResponseJson]
}
// This will call create customer ,then return the customerId
def createAndGetCustomerIdViaEndpoint(bankId:String, consumerAndToken: Option[(Consumer, Token)]) = {
private def createCustomer(bankId:String, userId: String) = {
val postCustomerJson = SwaggerDefinitionsJSON.postCustomerJsonV310
def createCustomer(consumerAndToken: Option[(Consumer, Token)]) ={
Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, CanCreateCustomer.toString)
When("We make a request v3.1.0")
val request310 = (v4_0_0_Request / "banks" / bankId / "customers").POST <@(user1)
val response310 = makePostRequest(request310, write(postCustomerJson))
Then("We should get a 201")
response310.code should equal(201)
response310.body.extract[CustomerJsonV310]
}
createCustomer(consumerAndToken).customer_id
Entitlement.entitlement.vend.addEntitlement(bankId, userId, CanCreateCustomer.toString)
When("We make a request v3.1.0")
val request310 = (v4_0_0_Request / "banks" / bankId / "customers").POST <@(user1)
val response310 = makePostRequest(request310, write(postCustomerJson))
Then("We should get a 201")
response310.code should equal(201)
response310.body.extract[CustomerJsonV310]
}
// This will call create customer ,then return the customerId
def createAndGetCustomerIdViaEndpoint(bankId:String, userId: String = resourceUser1.userId) = {
createCustomer(bankId, userId).customer_id
}
// This will call create customer ,then return the customerId
def createCustomerViaEndpointAndGetNumber(bankId:String, userId: String) = {
createCustomer(bankId, userId).customer_number
}
//This will call create user customer link