mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:26:51 +00:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
9e19f325d5
@ -5325,6 +5325,21 @@ object SwaggerDefinitionsJSON {
|
||||
|
||||
attributes = Some(List(atmAttributeResponseJsonV510))
|
||||
)
|
||||
|
||||
val userAttributeJsonV510 = UserAttributeJsonV510(
|
||||
name = userAttributeNameExample.value,
|
||||
`type` = userAttributeTypeExample.value,
|
||||
value = userAttributeValueExample.value
|
||||
)
|
||||
|
||||
val userAttributeResponseJsonV510 = UserAttributeResponseJsonV510(
|
||||
user_attribute_id = userAttributeIdExample.value,
|
||||
name = userAttributeNameExample.value,
|
||||
`type` = userAttributeTypeExample.value,
|
||||
value = userAttributeValueExample.value,
|
||||
is_personal = userAttributeIsPersonalExample.value.toBoolean,
|
||||
insert_date = new Date()
|
||||
)
|
||||
|
||||
val postAtmJsonV510 = PostAtmJsonV510(
|
||||
id = Some(atmIdExample.value),
|
||||
|
||||
@ -416,7 +416,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
}
|
||||
|
||||
private def extractAccountData(scheme: String, address: String): (String, String, String, String, String) = {
|
||||
val (iban: String, bban: String, pan: String, maskedPan: String, currency: String) = Connector.connector.vend.getBankAccountByRouting(
|
||||
val (iban: String, bban: String, pan: String, maskedPan: String, currency: String) = Connector.connector.vend.getBankAccountByRoutingLegacy(
|
||||
None,
|
||||
scheme,
|
||||
address,
|
||||
|
||||
@ -403,6 +403,15 @@ object ApiRole {
|
||||
|
||||
case class CanGetUsersWithAttributes (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetUsersWithAttributes = CanGetUsersWithAttributes()
|
||||
|
||||
case class CanCreateNonPersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canCreateNonPersonalUserAttribute = CanCreateNonPersonalUserAttribute()
|
||||
|
||||
case class CanGetNonPersonalUserAttributes (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetNonPersonalUserAttributes = CanGetNonPersonalUserAttributes()
|
||||
|
||||
case class CanDeleteNonPersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canDeleteNonPersonalUserAttribute = CanDeleteNonPersonalUserAttribute()
|
||||
|
||||
case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canReadUserLockedStatus = CanReadUserLockedStatus()
|
||||
|
||||
@ -553,9 +553,9 @@ object ErrorMessages {
|
||||
val InvalidChargePolicy = "OBP-40013: Invalid Charge Policy. Please specify a valid value for Charge_Policy: SHARED, SENDER or RECEIVER. "
|
||||
val AllowedAttemptsUsedUp = "OBP-40014: Sorry, you've used up your allowed attempts. "
|
||||
val InvalidChallengeType = "OBP-40015: Invalid Challenge Type. Please specify a valid value for CHALLENGE_TYPE, when you create the transaction request."
|
||||
val InvalidChallengeAnswer = "OBP-40016: Invalid Challenge Answer. Please specify a valid value for answer in Json body. " +
|
||||
"The challenge answer may be expired." +
|
||||
"Or you've used up your allowed attempts (3 times)." +
|
||||
val InvalidChallengeAnswer = s"OBP-40016: Invalid Challenge Answer. Please specify a valid value for answer in Json body. " +
|
||||
s"The challenge answer may be expired." +
|
||||
s"Or you've used up your allowed attempts." +
|
||||
"Or if connector = mapped and transactionRequestType_OTP_INSTRUCTION_TRANSPORT = DUMMY and suggested_default_sca_method=DUMMY, the answer must be `123`. " +
|
||||
"Or if connector = others, the challenge answer can be got by phone message or other security ways."
|
||||
val InvalidPhoneNumber = "OBP-40017: Invalid Phone Number. Please specify a valid value for PHONE_NUMBER. Eg:+9722398746 "
|
||||
|
||||
@ -149,10 +149,13 @@ object ExampleValue {
|
||||
lazy val customerAttributeValueExample = ConnectorField("123456789", s"Customer attribute value.")
|
||||
glossaryItems += makeGlossaryItem("Customer.attributeValue", customerAttributeValueExample)
|
||||
|
||||
lazy val userAttributeValueExample = ConnectorField("90", s"Uset attribute value.")
|
||||
lazy val userAttributeValueExample = ConnectorField("90", s"User attribute value.")
|
||||
glossaryItems += makeGlossaryItem("User.attributeValue", userAttributeValueExample)
|
||||
|
||||
lazy val labelExample = ConnectorField("My Account", s"A lable that describes the Account")
|
||||
lazy val userAttributeIsPersonalExample = ConnectorField("false", s"User attribute is personal value.")
|
||||
glossaryItems += makeGlossaryItem("User.isPersonal", userAttributeIsPersonalExample)
|
||||
|
||||
lazy val labelExample = ConnectorField("My Account", s"A label that describes the Account")
|
||||
lazy val legalNameExample = ConnectorField("Eveline Tripman", s"The legal name of the Customer.")
|
||||
glossaryItems += makeGlossaryItem("Customer.legalName", legalNameExample)
|
||||
|
||||
|
||||
@ -458,8 +458,8 @@ object NewStyle extends MdcLoggable{
|
||||
}
|
||||
|
||||
def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]) : OBPReturnType[BankAccount] = {
|
||||
Future(Connector.connector.vend.getBankAccountByRouting(bankId: Option[BankId], scheme: String, address : String, callContext: Option[CallContext])) map { i =>
|
||||
unboxFullOrFail(i, callContext,s"$BankAccountNotFoundByAccountRouting Current scheme is $scheme, current address is $address, current bankId is $bankId", 404 )
|
||||
Connector.connector.vend.getBankAccountByRouting(bankId: Option[BankId], scheme: String, address : String, callContext: Option[CallContext]) map { i =>
|
||||
(unboxFullOrFail(i._1, callContext,s"$BankAccountNotFoundByAccountRouting Current scheme is $scheme, current address is $address, current bankId is $bankId", 404 ), i._2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,7 +1356,11 @@ object NewStyle extends MdcLoggable{
|
||||
|
||||
def validateChallengeAnswer(challengeId: String, hashOfSuppliedAnswer: String, callContext: Option[CallContext]): OBPReturnType[Boolean] =
|
||||
Connector.connector.vend.validateChallengeAnswer(challengeId: String, hashOfSuppliedAnswer: String, callContext: Option[CallContext]) map { i =>
|
||||
(unboxFullOrFail(i._1, callContext, s"$InvalidChallengeAnswer "), i._2)
|
||||
(unboxFullOrFail(i._1, callContext, s"${
|
||||
InvalidChallengeAnswer
|
||||
.replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
}"), i._2)
|
||||
}
|
||||
|
||||
def allChallengesSuccessfullyAnswered(
|
||||
@ -1399,7 +1403,11 @@ object NewStyle extends MdcLoggable{
|
||||
hashOfSuppliedAnswer: String,
|
||||
callContext: Option[CallContext]
|
||||
) map { i =>
|
||||
(unboxFullOrFail(i._1, callContext, s"$InvalidChallengeAnswer "), i._2)
|
||||
(unboxFullOrFail(i._1, callContext, s"${
|
||||
InvalidChallengeAnswer
|
||||
.replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
}"), i._2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1888,6 +1896,23 @@ object NewStyle extends MdcLoggable{
|
||||
}
|
||||
}
|
||||
|
||||
def getPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[List[UserAttribute]] = {
|
||||
Connector.connector.vend.getPersonalUserAttributes(
|
||||
userId: String, callContext: Option[CallContext]
|
||||
) map {
|
||||
i => (connectorEmptyResponse(i._1, callContext), i._2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getNonPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[List[UserAttribute]] = {
|
||||
Connector.connector.vend.getNonPersonalUserAttributes(
|
||||
userId: String, callContext: Option[CallContext]
|
||||
) map {
|
||||
i => (connectorEmptyResponse(i._1, callContext), i._2)
|
||||
}
|
||||
}
|
||||
|
||||
def getUserAttributesByUsers(userIds: List[String], callContext: Option[CallContext]): OBPReturnType[List[UserAttribute]] = {
|
||||
Connector.connector.vend.getUserAttributesByUsers(
|
||||
userIds, callContext: Option[CallContext]
|
||||
@ -1901,6 +1926,7 @@ object NewStyle extends MdcLoggable{
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String,
|
||||
isPersonal: Boolean,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[UserAttribute] = {
|
||||
Connector.connector.vend.createOrUpdateUserAttribute(
|
||||
@ -1909,6 +1935,7 @@ object NewStyle extends MdcLoggable{
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String,
|
||||
isPersonal: Boolean,
|
||||
callContext: Option[CallContext]
|
||||
) map {
|
||||
i => (connectorEmptyResponse(i._1, callContext), i._2)
|
||||
|
||||
@ -95,6 +95,7 @@ object Migration extends MdcLoggable {
|
||||
dropConsentAuthContextDropIndex()
|
||||
alterMappedExpectedChallengeAnswerChallengeTypeLength()
|
||||
alterTransactionRequestChallengeChallengeTypeLength()
|
||||
alterUserAttributeNameLength()
|
||||
alterMappedCustomerAttribute(startedBeforeSchemifier)
|
||||
dropMappedBadLoginAttemptIndex()
|
||||
}
|
||||
@ -421,6 +422,13 @@ object Migration extends MdcLoggable {
|
||||
MigrationOfTransactionRequestChallengeChallengeTypeLength.alterColumnChallengeChallengeTypeLength(name)
|
||||
}
|
||||
}
|
||||
|
||||
private def alterUserAttributeNameLength(): Boolean = {
|
||||
val name = nameOf(alterUserAttributeNameLength)
|
||||
runOnce(name) {
|
||||
MigrationOfUserAttributeNameFieldLength.alterNameLength(name)
|
||||
}
|
||||
}
|
||||
private def alterMappedCustomerAttribute(startedBeforeSchemifier: Boolean): Boolean = {
|
||||
if(startedBeforeSchemifier == true) {
|
||||
logger.warn(s"Migration.database.alterMappedCustomerAttribute(true) cannot be run before Schemifier.")
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
package code.api.util.migration
|
||||
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.migration.Migration.{DbFunction, saveLog}
|
||||
import code.users.UserAttribute
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.mapper.{DB, Schemifier}
|
||||
import net.liftweb.util.DefaultConnectionIdentifier
|
||||
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.{ZoneId, ZonedDateTime}
|
||||
|
||||
object MigrationOfUserAttributeNameFieldLength {
|
||||
|
||||
val oneDayAgo = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1)
|
||||
val oneYearInFuture = ZonedDateTime.now(ZoneId.of("UTC")).plusYears(1)
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
|
||||
|
||||
def alterNameLength(name: String): Boolean = {
|
||||
DbFunction.tableExists(UserAttribute, (DB.use(DefaultConnectionIdentifier){ conn => conn})) match {
|
||||
case true =>
|
||||
val startDate = System.currentTimeMillis()
|
||||
val commitId: String = APIUtil.gitCommit
|
||||
var isSuccessful = false
|
||||
|
||||
val executedSql =
|
||||
DbFunction.maybeWrite(true, Schemifier.infoF _, DB.use(DefaultConnectionIdentifier){ conn => conn}) {
|
||||
APIUtil.getPropsValue("db.driver") match {
|
||||
case Full(value) if value.contains("com.microsoft.sqlserver.jdbc.SQLServerDriver") =>
|
||||
() =>
|
||||
"""
|
||||
|ALTER TABLE UserAttribute ALTER COLUMN name varchar(255);
|
||||
|""".stripMargin
|
||||
case _ =>
|
||||
() =>
|
||||
"""
|
||||
|ALTER TABLE UserAttribute ALTER COLUMN name type varchar(255);
|
||||
|""".stripMargin
|
||||
}
|
||||
}
|
||||
|
||||
val endDate = System.currentTimeMillis()
|
||||
val comment: String =
|
||||
s"""Executed SQL:
|
||||
|$executedSql
|
||||
|""".stripMargin
|
||||
isSuccessful = true
|
||||
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
|
||||
isSuccessful
|
||||
|
||||
case false =>
|
||||
val startDate = System.currentTimeMillis()
|
||||
val commitId: String = APIUtil.gitCommit
|
||||
val isSuccessful = false
|
||||
val endDate = System.currentTimeMillis()
|
||||
val comment: String =
|
||||
s"""${UserAttribute._dbTableNameLC} table does not exist""".stripMargin
|
||||
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
|
||||
isSuccessful
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -644,7 +644,10 @@ trait APIMethods210 {
|
||||
|
||||
(isChallengeAnswerValidated, callContext) <- NewStyle.function.validateChallengeAnswer(challengeAnswerJson.id, challengeAnswerJson.answer, callContext)
|
||||
|
||||
_ <- Helper.booleanToFuture(s"${InvalidChallengeAnswer} ", cc=callContext) {
|
||||
_ <- Helper.booleanToFuture(s"${InvalidChallengeAnswer
|
||||
.replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
} ", cc = callContext) {
|
||||
(isChallengeAnswerValidated == true)
|
||||
}
|
||||
|
||||
|
||||
@ -1630,7 +1630,10 @@ trait APIMethods400 {
|
||||
|
||||
(challengeAnswerIsValidated, callContext) <- NewStyle.function.validateChallengeAnswer(challengeAnswerJson.id, challengeAnswerJson.answer, callContext)
|
||||
|
||||
_ <- Helper.booleanToFuture(s"${InvalidChallengeAnswer.replace("answer may be expired.",s"answer may be expired, current expiration time is ${transactionRequestChallengeTtl} seconds .")} ", cc=callContext) {
|
||||
_ <- Helper.booleanToFuture(s"${InvalidChallengeAnswer
|
||||
.replace("answer may be expired.",s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.",s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
}", cc=callContext) {
|
||||
challengeAnswerIsValidated
|
||||
}
|
||||
|
||||
@ -8738,13 +8741,13 @@ trait APIMethods400 {
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
getCurrentUserAttributes,
|
||||
getMyPersonalUserAttributes,
|
||||
implementedInApiVersion,
|
||||
nameOf(getCurrentUserAttributes),
|
||||
nameOf(getMyPersonalUserAttributes),
|
||||
"GET",
|
||||
"/my/user/attributes",
|
||||
"Get User Attributes for current user",
|
||||
s"""Get User Attributes for current user.
|
||||
"Get My Personal User Attributes",
|
||||
s"""Get My Personal User Attributes.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|""".stripMargin,
|
||||
@ -8757,11 +8760,11 @@ trait APIMethods400 {
|
||||
List(apiTagUser)
|
||||
)
|
||||
|
||||
lazy val getCurrentUserAttributes: OBPEndpoint = {
|
||||
lazy val getMyPersonalUserAttributes: OBPEndpoint = {
|
||||
case "my" :: "user" :: "attributes" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(attributes, callContext) <- NewStyle.function.getUserAttributes(cc.userId, cc.callContext)
|
||||
(attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(cc.userId, cc.callContext)
|
||||
} yield {
|
||||
(JSONFactory400.createUserAttributesJson(attributes), HttpCode.`200`(callContext))
|
||||
}
|
||||
@ -8775,7 +8778,7 @@ trait APIMethods400 {
|
||||
nameOf(getUserWithAttributes),
|
||||
"GET",
|
||||
"/users/USER_ID/attributes",
|
||||
"Get User Attributes for the user",
|
||||
"Get User with Attributes by USER_ID",
|
||||
s"""Get User Attributes for the user defined via USER_ID.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
@ -8795,7 +8798,7 @@ trait APIMethods400 {
|
||||
cc =>
|
||||
for {
|
||||
(user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
|
||||
(attributes, callContext) <- NewStyle.function.getUserAttributes(userId, callContext)
|
||||
(attributes, callContext) <- NewStyle.function.getUserAttributes(user.userId, callContext)
|
||||
} yield {
|
||||
(JSONFactory400.createUserWithAttributesJson(user, attributes), HttpCode.`200`(callContext))
|
||||
}
|
||||
@ -8804,15 +8807,15 @@ trait APIMethods400 {
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createCurrentUserAttribute,
|
||||
createMyPersonalUserAttribute,
|
||||
implementedInApiVersion,
|
||||
nameOf(createCurrentUserAttribute),
|
||||
nameOf(createMyPersonalUserAttribute),
|
||||
"POST",
|
||||
"/my/user/attributes",
|
||||
"Create User Attribute for current user",
|
||||
s""" Create User Attribute for current user
|
||||
"Create My Personal User Attribute",
|
||||
s""" Create My Personal User Attribute
|
||||
|
|
||||
|The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
|
||||
|The `type` field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
@ -8827,18 +8830,17 @@ trait APIMethods400 {
|
||||
List(apiTagUser),
|
||||
Some(List()))
|
||||
|
||||
lazy val createCurrentUserAttribute : OBPEndpoint = {
|
||||
lazy val createMyPersonalUserAttribute : OBPEndpoint = {
|
||||
case "my" :: "user" :: "attributes" :: Nil JsonPost json -> _=> {
|
||||
cc =>
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400 "
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 "
|
||||
for {
|
||||
(attributes, callContext) <- NewStyle.function.getUserAttributes(cc.userId, cc.callContext)
|
||||
postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
json.extract[TransactionAttributeJsonV400]
|
||||
postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
json.extract[UserAttributeJsonV400]
|
||||
}
|
||||
failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
|
||||
s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)"
|
||||
userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
s"${TransactionAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
|
||||
userAttributeType <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
UserAttributeType.withName(postedData.`type`)
|
||||
}
|
||||
(userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
|
||||
@ -8847,7 +8849,8 @@ trait APIMethods400 {
|
||||
postedData.name,
|
||||
userAttributeType,
|
||||
postedData.value,
|
||||
callContext
|
||||
true,
|
||||
cc.callContext
|
||||
)
|
||||
} yield {
|
||||
(JSONFactory400.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext))
|
||||
@ -8856,13 +8859,13 @@ trait APIMethods400 {
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
updateCurrentUserAttribute,
|
||||
updateMyPersonalUserAttribute,
|
||||
implementedInApiVersion,
|
||||
nameOf(updateCurrentUserAttribute),
|
||||
nameOf(updateMyPersonalUserAttribute),
|
||||
"PUT",
|
||||
"/my/user/attributes/USER_ATTRIBUTE_ID",
|
||||
"Update User Attribute for current user",
|
||||
s"""Update User Attribute for current user by USER_ATTRIBUTE_ID
|
||||
"Update My Personal User Attribute",
|
||||
s"""Update My Personal User Attribute for current user by USER_ATTRIBUTE_ID
|
||||
|
|
||||
|The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
|
||||
|
|
||||
@ -8879,21 +8882,20 @@ trait APIMethods400 {
|
||||
List(apiTagUser),
|
||||
Some(List()))
|
||||
|
||||
lazy val updateCurrentUserAttribute : OBPEndpoint = {
|
||||
lazy val updateMyPersonalUserAttribute : OBPEndpoint = {
|
||||
case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut json -> _=> {
|
||||
cc =>
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $TransactionAttributeJsonV400 "
|
||||
for {
|
||||
(attributes, callContext) <- NewStyle.function.getUserAttributes(cc.userId, cc.callContext)
|
||||
(attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(cc.userId, cc.callContext)
|
||||
failMsg = s"$UserAttributeNotFound"
|
||||
_ <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
attributes.exists(_.userAttributeId == userAttributeId)
|
||||
}
|
||||
postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
json.extract[TransactionAttributeJsonV400]
|
||||
postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 ", 400, callContext) {
|
||||
json.extract[UserAttributeJsonV400]
|
||||
}
|
||||
failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
|
||||
s"${TransactionAttributeType.DOUBLE}(12.1234), ${TransactionAttributeType.STRING}(TAX_NUMBER), ${TransactionAttributeType.INTEGER} (123)and ${TransactionAttributeType.DATE_WITH_DAY}(2012-04-23)"
|
||||
s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
|
||||
userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
UserAttributeType.withName(postedData.`type`)
|
||||
}
|
||||
@ -8903,6 +8905,7 @@ trait APIMethods400 {
|
||||
postedData.name,
|
||||
userAttributeType,
|
||||
postedData.value,
|
||||
true,
|
||||
callContext
|
||||
)
|
||||
} yield {
|
||||
|
||||
@ -15,8 +15,9 @@ import code.api.v3_0_0.JSONFactory300
|
||||
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
|
||||
import code.api.v3_1_0.ConsentJsonV310
|
||||
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
|
||||
import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400}
|
||||
import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400, UserAttributeJsonV400}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.bankconnectors.Connector
|
||||
import code.consent.Consents
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.metrics.APIMetrics
|
||||
@ -29,7 +30,7 @@ import code.views.system.{AccountAccess, ViewDefinition}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.model.{AtmId, AtmT, BankId}
|
||||
import com.openbankproject.commons.model.enums.AtmAttributeType
|
||||
import com.openbankproject.commons.model.enums.{AtmAttributeType, UserAttributeType}
|
||||
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.S
|
||||
@ -152,7 +153,139 @@ trait APIMethods510 {
|
||||
(JSONFactory400.createApiCollectionsJsonV400(apiCollections), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createNonPersonalUserAttribute,
|
||||
implementedInApiVersion,
|
||||
nameOf(createNonPersonalUserAttribute),
|
||||
"POST",
|
||||
"/users/USER_ID/non-personal/attributes",
|
||||
"Create Non Personal User Attribute",
|
||||
s""" Create Non Personal User Attribute
|
||||
|
|
||||
|The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY"
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""",
|
||||
userAttributeJsonV510,
|
||||
userAttributeResponseJsonV510,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
InvalidJsonFormat,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canCreateNonPersonalUserAttribute))
|
||||
)
|
||||
|
||||
lazy val createNonPersonalUserAttribute: OBPEndpoint = {
|
||||
case "users" :: userId ::"non-personal":: "attributes" :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV510 "
|
||||
for {
|
||||
(user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext)
|
||||
postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
json.extract[UserAttributeJsonV510]
|
||||
}
|
||||
failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " +
|
||||
s"${UserAttributeType.DOUBLE}(12.1234), ${UserAttributeType.STRING}(TAX_NUMBER), ${UserAttributeType.INTEGER} (123)and ${UserAttributeType.DATE_WITH_DAY}(2012-04-23)"
|
||||
userAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
UserAttributeType.withName(postedData.`type`)
|
||||
}
|
||||
(userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute(
|
||||
user.userId,
|
||||
None,
|
||||
postedData.name,
|
||||
userAttributeType,
|
||||
postedData.value,
|
||||
false,
|
||||
callContext
|
||||
)
|
||||
} yield {
|
||||
(JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
deleteNonPersonalUserAttribute,
|
||||
implementedInApiVersion,
|
||||
nameOf(deleteNonPersonalUserAttribute),
|
||||
"DELETE",
|
||||
"/users/USER_ID/non-personal/attributes/USER_ATTRIBUTE_ID",
|
||||
"Delete Non Personal User Attribute",
|
||||
s"""Delete the Non Personal User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
EmptyBody,
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
InvalidConnectorResponse,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canDeleteNonPersonalUserAttribute)))
|
||||
|
||||
lazy val deleteNonPersonalUserAttribute: OBPEndpoint = {
|
||||
case "users" :: userId :: "non-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => {
|
||||
cc =>
|
||||
for {
|
||||
(_, callContext) <- authenticatedAccess(cc)
|
||||
(_, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
|
||||
(deleted,callContext) <- Connector.connector.vend.deleteUserAttribute(
|
||||
userAttributeId: String,
|
||||
callContext: Option[CallContext]
|
||||
) map {
|
||||
i => (connectorEmptyResponse (i._1, callContext), i._2)
|
||||
}
|
||||
} yield {
|
||||
(Full(deleted), HttpCode.`204`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getNonPersonalUserAttributes,
|
||||
implementedInApiVersion,
|
||||
nameOf(getNonPersonalUserAttributes),
|
||||
"GET",
|
||||
"/users/USER_ID/non-personal/attributes",
|
||||
"Get Non Personal User Attributes",
|
||||
s"""Get Non Personal User Attribute for a user specified by USER_ID
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
EmptyBody,
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
InvalidConnectorResponse,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canGetNonPersonalUserAttributes)))
|
||||
|
||||
lazy val getNonPersonalUserAttributes: OBPEndpoint = {
|
||||
case "users" :: userId :: "non-personal" ::"attributes" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(_, callContext) <- authenticatedAccess(cc)
|
||||
(user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext)
|
||||
(userAttributes,callContext) <- NewStyle.function.getNonPersonalUserAttributes(
|
||||
user.userId,
|
||||
callContext,
|
||||
)
|
||||
} yield {
|
||||
(JSONFactory510.createUserAttributesJson(userAttributes), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
|
||||
@ -35,10 +35,12 @@ import code.api.v3_0_0.{AddressJsonV300, OpeningTimesV300}
|
||||
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.atms.Atms.Atm
|
||||
import code.users.UserAttribute
|
||||
import code.views.system.{AccountAccess, ViewDefinition}
|
||||
import com.openbankproject.commons.model.{Address, AtmId, AtmT, BankId, Location, Meta}
|
||||
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
|
||||
|
||||
import java.util.Date
|
||||
import scala.collection.immutable.List
|
||||
import scala.util.Try
|
||||
|
||||
@ -194,6 +196,26 @@ case class AtmAttributeResponseJsonV510(
|
||||
)
|
||||
case class AtmAttributesResponseJsonV510(atm_attributes: List[AtmAttributeResponseJsonV510])
|
||||
|
||||
case class UserAttributeResponseJsonV510(
|
||||
user_attribute_id: String,
|
||||
name: String,
|
||||
`type`: String,
|
||||
value: String,
|
||||
is_personal: Boolean,
|
||||
insert_date: Date
|
||||
)
|
||||
|
||||
case class UserAttributeJsonV510(
|
||||
name: String,
|
||||
`type`: String,
|
||||
value: String
|
||||
)
|
||||
|
||||
case class UserAttributesResponseJsonV510(
|
||||
user_attributes: List[UserAttributeResponseJsonV510]
|
||||
)
|
||||
|
||||
|
||||
|
||||
object JSONFactory510 {
|
||||
|
||||
@ -450,6 +472,19 @@ object JSONFactory510 {
|
||||
def createAtmAttributesJson(atmAttributes: List[AtmAttribute]): AtmAttributesResponseJsonV510 =
|
||||
AtmAttributesResponseJsonV510(atmAttributes.map(createAtmAttributeJson))
|
||||
|
||||
|
||||
def createUserAttributeJson(userAttribute: UserAttribute): UserAttributeResponseJsonV510 = {
|
||||
UserAttributeResponseJsonV510(
|
||||
user_attribute_id = userAttribute.userAttributeId,
|
||||
name = userAttribute.name,
|
||||
`type` = userAttribute.attributeType.toString,
|
||||
value = userAttribute.value,
|
||||
insert_date = userAttribute.insertDate,
|
||||
is_personal = userAttribute.isPersonal
|
||||
)
|
||||
}
|
||||
|
||||
def createUserAttributesJson(userAttribute: List[UserAttribute]): UserAttributesResponseJsonV510 = {
|
||||
UserAttributesResponseJsonV510(userAttribute.map(createUserAttributeJson))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -523,7 +523,8 @@ trait Connector extends MdcLoggable {
|
||||
|
||||
def getBankAccountByAccountId(accountId : AccountId, callContext: Option[CallContext]) : OBPReturnType[Box[BankAccount]]= Future{(Failure(setUnimplementedError),callContext)}
|
||||
def getBankAccountByIban(iban : String, callContext: Option[CallContext]) : OBPReturnType[Box[BankAccount]]= Future{(Failure(setUnimplementedError),callContext)}
|
||||
def getBankAccountByRouting(bankId: Option[BankId], scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
|
||||
def getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
|
||||
def getBankAccountByRouting(bankId: Option[BankId], scheme : String, address : String, callContext: Option[CallContext]) : OBPReturnType[Box[BankAccount]]= Future{(Failure(setUnimplementedError), callContext)}
|
||||
def getAccountRoutingsByScheme(bankId: Option[BankId], scheme : String, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccountRouting]]] = Future{(Failure(setUnimplementedError),callContext)}
|
||||
def getAccountRouting(bankId: Option[BankId], scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccountRouting, Option[CallContext])]= Failure(setUnimplementedError)
|
||||
|
||||
@ -2260,6 +2261,12 @@ trait Connector extends MdcLoggable {
|
||||
def getUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] =
|
||||
Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] =
|
||||
Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getNonPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] =
|
||||
Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getUserAttributesByUsers(userIds: List[String], callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] =
|
||||
Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
@ -2269,9 +2276,15 @@ trait Connector extends MdcLoggable {
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String,
|
||||
isPersonal: Boolean,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[Box[UserAttribute]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def deleteUserAttribute(
|
||||
userAttributeId: String,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[Box[Boolean]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def createOrUpdateTransactionAttribute(
|
||||
bankId: BankId,
|
||||
transactionId: TransactionId,
|
||||
|
||||
@ -219,6 +219,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
val userAttributeName = s"TRANSACTION_REQUESTS_PAYMENT_LIMIT_${currency}_" + transactionRequestType.toUpperCase
|
||||
val userAttributes = UserAttribute.findAll(
|
||||
By(UserAttribute.UserId, userId),
|
||||
By(UserAttribute.IsPersonal, false),
|
||||
OrderBy(UserAttribute.createdAt, Descending)
|
||||
)
|
||||
val userAttributeValue = userAttributes.find(_.name == userAttributeName).map(_.value)
|
||||
@ -759,10 +760,10 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
}
|
||||
|
||||
override def getBankAccountByIban(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = Future {
|
||||
getBankAccountByRouting(None, "IBAN", iban, callContext)
|
||||
getBankAccountByRoutingLegacy(None, "IBAN", iban, callContext)
|
||||
}
|
||||
|
||||
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
override def getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
bankId match {
|
||||
case Some(bankId) =>
|
||||
BankAccountRouting
|
||||
@ -775,6 +776,11 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
}
|
||||
}
|
||||
|
||||
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = Future {
|
||||
getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext])
|
||||
}
|
||||
|
||||
|
||||
override def getAccountRoutingsByScheme(bankId: Option[BankId], scheme: String, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccountRouting]]] = {
|
||||
Future {
|
||||
Full(bankId match {
|
||||
@ -1785,7 +1791,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
|
||||
for {
|
||||
toAccount <-
|
||||
Connector.connector.vend.getBankAccountByRouting(None, toAccountRoutingScheme, toAccountRoutingAddress, None) match {
|
||||
Connector.connector.vend.getBankAccountByRoutingLegacy(None, toAccountRoutingScheme, toAccountRoutingAddress, None) match {
|
||||
case Full(bankAccount) => Future.successful(bankAccount._1)
|
||||
case _: EmptyBox =>
|
||||
NewStyle.function.getCounterpartyByIban(toAccountRoutingAddress, callContext).flatMap(counterparty =>
|
||||
@ -4077,15 +4083,26 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
override def getUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.getUserAttributesByUser(userId: String) map {(_, callContext)}
|
||||
}
|
||||
|
||||
override def getNonPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.getNonPersonalUserAttributes(userId: String) map {(_, callContext)}
|
||||
}
|
||||
override def getPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.getPersonalUserAttributes(userId: String) map {(_, callContext)}
|
||||
}
|
||||
override def getUserAttributesByUsers(userIds: List[String], callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.getUserAttributesByUsers(userIds) map {(_, callContext)}
|
||||
}
|
||||
override def deleteUserAttribute(userAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.deleteUserAttribute(userAttributeId) map {(_, callContext)}
|
||||
}
|
||||
override def createOrUpdateUserAttribute(
|
||||
userId: String,
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String,
|
||||
isPersonal: Boolean,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[Box[UserAttribute]] = {
|
||||
UserAttributeProvider.userAttributeProvider.vend.createOrUpdateUserAttribute(
|
||||
@ -4093,7 +4110,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String
|
||||
value: String,
|
||||
isPersonal: Boolean
|
||||
) map {
|
||||
(_, callContext)
|
||||
}
|
||||
|
||||
@ -958,7 +958,7 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
override def getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
import com.openbankproject.commons.dto.{InBoundGetBankAccountByRouting => InBound, OutBoundGetBankAccountByRouting => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address)
|
||||
val response: Future[Box[InBound]] = (southSideActor ? req).mapTo[InBound].recoverWith(recoverFunction).map(Box !! _)
|
||||
|
||||
@ -887,7 +887,7 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
override def getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
import com.openbankproject.commons.dto.{InBoundGetBankAccountByRouting => InBound, OutBoundGetBankAccountByRouting => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address)
|
||||
val response: Future[Box[InBound]] = sendRequest[InBound](getUrl(callContext, "getBankAccountByRouting"), HttpMethods.POST, req, callContext)
|
||||
|
||||
@ -866,7 +866,7 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
override def getBankAccountByRoutingLegacy(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
|
||||
import com.openbankproject.commons.dto.{InBoundGetBankAccountByRouting => InBound, OutBoundGetBankAccountByRouting => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address)
|
||||
val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_by_routing", req, callContext)
|
||||
|
||||
@ -19,14 +19,24 @@ object RemotedataUserAttribute extends ObpActorInit with UserAttributeProvider {
|
||||
override def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]] =
|
||||
(actor ? cc.getUserAttributesByUser(userId)).mapTo[Box[List[UserAttribute]]]
|
||||
|
||||
override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] =
|
||||
(actor ? cc.getPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]]
|
||||
|
||||
override def getNonPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] =
|
||||
(actor ? cc.getNonPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]]
|
||||
|
||||
override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] =
|
||||
(actor ? cc.getUserAttributesByUsers(userIds)).mapTo[Box[List[UserAttribute]]]
|
||||
|
||||
override def deleteUserAttribute(userAttributeId: String): Future[Box[Boolean]] =
|
||||
(actor ? cc.deleteUserAttribute(userAttributeId: String)).mapTo[Box[Boolean]]
|
||||
|
||||
override def createOrUpdateUserAttribute(userId: String,
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String): Future[Box[UserAttribute]] =
|
||||
(actor ? cc.createOrUpdateUserAttribute(userId, userAttributeId, name, attributeType, value )).mapTo[Box[UserAttribute]]
|
||||
value: String,
|
||||
isPersonal: Boolean): Future[Box[UserAttribute]] =
|
||||
(actor ? cc.createOrUpdateUserAttribute(userId, userAttributeId, name, attributeType, value, isPersonal)).mapTo[Box[UserAttribute]]
|
||||
|
||||
}
|
||||
|
||||
@ -23,9 +23,13 @@ class RemotedataUserAttributeActor extends Actor with ObpActorHelper with MdcLog
|
||||
logger.debug(s"getUserAttributesByUser(${userIds})")
|
||||
mapper.getUserAttributesByUsers(userIds) pipeTo sender
|
||||
|
||||
case cc.createOrUpdateUserAttribute(userId: String, userAttributeId: Option[String], name: String, attributeType: UserAttributeType.Value, value: String) =>
|
||||
logger.debug(s"createOrUpdateUserAttribute(${userId}, ${userAttributeId}, ${name}, ${attributeType}, ${value})")
|
||||
mapper.createOrUpdateUserAttribute(userId, userAttributeId, name, attributeType, value) pipeTo sender
|
||||
case cc.createOrUpdateUserAttribute(
|
||||
userId: String, userAttributeId: Option[String], name: String,
|
||||
attributeType: UserAttributeType.Value, value: String,
|
||||
isPersonal: Boolean
|
||||
) =>
|
||||
logger.debug(s"createOrUpdateUserAttribute(${userId}, ${userAttributeId}, ${name}, ${attributeType}, ${value}, ${isPersonal})")
|
||||
mapper.createOrUpdateUserAttribute(userId, userAttributeId, name, attributeType, value, isPersonal) pipeTo sender
|
||||
|
||||
case message => logger.warn("[AKKA ACTOR ERROR - REQUEST NOT RECOGNIZED] " + message)
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ trait OBPDataImport extends MdcLoggable {
|
||||
val ibans = data.accounts.map(_.IBAN)
|
||||
val duplicateIbans = ibans diff ibans.distinct
|
||||
val existingIbans = data.accounts.flatMap(acc => {
|
||||
Connector.connector.vend.getBankAccountByRouting(Some(BankId(acc.bank)), AccountRoutingScheme.IBAN.toString, acc.IBAN, None).map(_._1)
|
||||
Connector.connector.vend.getBankAccountByRoutingLegacy(Some(BankId(acc.bank)), AccountRoutingScheme.IBAN.toString, acc.IBAN, None).map(_._1)
|
||||
})
|
||||
|
||||
if(!banksNotSpecifiedInImport.isEmpty) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package code.transactionChallenge
|
||||
|
||||
import code.api.util.APIUtil.transactionRequestChallengeTtl
|
||||
import code.api.util.APIUtil.{allowedAnswerTransactionRequestChallengeAttempts, transactionRequestChallengeTtl}
|
||||
import code.api.util.ErrorMessages.InvalidChallengeAnswer
|
||||
import code.api.util.{APIUtil, ErrorMessages}
|
||||
import com.openbankproject.commons.model.{ChallengeTrait, ErrorMessage}
|
||||
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA
|
||||
@ -77,13 +78,23 @@ object MappedChallengeProvider extends ChallengeProvider {
|
||||
if(currentHashedAnswer==expectedHashedAnswer) {
|
||||
tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()}
|
||||
} else {
|
||||
Failure(s"${ErrorMessages.InvalidChallengeAnswer}")
|
||||
Failure(s"${
|
||||
s"${
|
||||
InvalidChallengeAnswer
|
||||
.replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
}"}")
|
||||
}
|
||||
case Some(id) =>
|
||||
if(currentHashedAnswer==expectedHashedAnswer && id==challenge.expectedUserId) {
|
||||
tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()}
|
||||
} else {
|
||||
Failure(s"${ErrorMessages.InvalidChallengeAnswer}")
|
||||
Failure(s"${
|
||||
s"${
|
||||
InvalidChallengeAnswer
|
||||
.replace("answer may be expired.", s"answer may be expired (${transactionRequestChallengeTtl} seconds).")
|
||||
.replace("up your allowed attempts.", s"up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts} times).")
|
||||
}"}")
|
||||
}
|
||||
}
|
||||
}else{
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package code.users
|
||||
|
||||
import java.util.Date
|
||||
import code.api.util.ErrorMessages
|
||||
|
||||
import java.util.Date
|
||||
import code.util.MappedUUID
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.model.UserAttributeTrait
|
||||
@ -19,18 +20,47 @@ object MappedUserAttributeProvider extends UserAttributeProvider {
|
||||
UserAttribute.findAll(By(UserAttribute.UserId, userId))
|
||||
)
|
||||
}
|
||||
override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future {
|
||||
tryo(
|
||||
UserAttribute.findAll(
|
||||
By(UserAttribute.UserId, userId),
|
||||
By(UserAttribute.IsPersonal, true),
|
||||
OrderBy(UserAttribute.createdAt, Descending)
|
||||
)
|
||||
)
|
||||
}
|
||||
override def getNonPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future {
|
||||
tryo(
|
||||
UserAttribute.findAll(
|
||||
By(UserAttribute.UserId, userId),
|
||||
By(UserAttribute.IsPersonal, false),
|
||||
OrderBy(UserAttribute.createdAt, Descending)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] = Future {
|
||||
tryo(
|
||||
UserAttribute.findAll(ByList(UserAttribute.UserId, userIds))
|
||||
)
|
||||
}
|
||||
|
||||
override def deleteUserAttribute(userAttributeId: String): Future[Box[Boolean]] = {
|
||||
Future {
|
||||
UserAttribute.find(By(UserAttribute.UserAttributeId, userAttributeId)) match {
|
||||
case Full(t) => Full(t.delete_!)
|
||||
case Empty => Empty ?~! ErrorMessages.UserAttributeNotFound
|
||||
case _ => Full(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def createOrUpdateUserAttribute(userId: String,
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String): Future[Box[UserAttribute]] = {
|
||||
value: String,
|
||||
isPersonal: Boolean): Future[Box[UserAttribute]] = {
|
||||
userAttributeId match {
|
||||
case Some(id) => Future {
|
||||
UserAttribute.find(By(UserAttribute.UserAttributeId, id)) match {
|
||||
@ -40,6 +70,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider {
|
||||
.Name(name)
|
||||
.Type(attributeType.toString)
|
||||
.`Value`(value)
|
||||
// .IsPersonal(isPersonal) //Can not update this field in update ne
|
||||
.saveMe()
|
||||
}
|
||||
case _ => Empty
|
||||
@ -52,6 +83,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider {
|
||||
.Name(name)
|
||||
.Type(attributeType.toString())
|
||||
.`Value`(value)
|
||||
.IsPersonal(isPersonal)
|
||||
.saveMe()
|
||||
}
|
||||
}
|
||||
@ -65,9 +97,12 @@ class UserAttribute extends UserAttributeTrait with LongKeyedMapper[UserAttribut
|
||||
override def getSingleton = UserAttribute
|
||||
object UserAttributeId extends MappedUUID(this)
|
||||
object UserId extends MappedUUID(this)
|
||||
object Name extends MappedString(this, 50)
|
||||
object Name extends MappedString(this, 255)
|
||||
object Type extends MappedString(this, 50)
|
||||
object `Value` extends MappedString(this, 255)
|
||||
object IsPersonal extends MappedBoolean(this) {
|
||||
override def defaultValue = true
|
||||
}
|
||||
|
||||
override def userAttributeId: String = UserAttributeId.get
|
||||
override def userId: String = UserId.get
|
||||
@ -75,6 +110,7 @@ class UserAttribute extends UserAttributeTrait with LongKeyedMapper[UserAttribut
|
||||
override def attributeType: UserAttributeType.Value = UserAttributeType.withName(Type.get)
|
||||
override def value: String = `Value`.get
|
||||
override def insertDate: Date = createdAt.get
|
||||
override def isPersonal: Boolean = IsPersonal.get
|
||||
}
|
||||
|
||||
object UserAttribute extends UserAttribute with LongKeyedMetaMapper[UserAttribute] {
|
||||
|
||||
@ -38,23 +38,31 @@ trait UserAttributeProvider {
|
||||
private val logger = Logger(classOf[UserAttributeProvider])
|
||||
|
||||
def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]]
|
||||
def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]]
|
||||
def getNonPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]]
|
||||
def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]]
|
||||
def deleteUserAttribute(userAttributeId: String): Future[Box[Boolean]]
|
||||
def createOrUpdateUserAttribute(userId: String,
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String): Future[Box[UserAttribute]]
|
||||
value: String,
|
||||
isPersonal: Boolean): Future[Box[UserAttribute]]
|
||||
// End of Trait
|
||||
}
|
||||
|
||||
class RemotedataUserAttributeCaseClasses {
|
||||
case class getUserAttributesByUser(userId: String)
|
||||
case class getPersonalUserAttributes(userId: String)
|
||||
case class getNonPersonalUserAttributes(userId: String)
|
||||
case class deleteUserAttribute(userAttributeId: String)
|
||||
case class getUserAttributesByUsers(userIds: List[String])
|
||||
case class createOrUpdateUserAttribute(userId: String,
|
||||
userAttributeId: Option[String],
|
||||
name: String,
|
||||
attributeType: UserAttributeType.Value,
|
||||
value: String)
|
||||
value: String,
|
||||
isPersonal: Boolean)
|
||||
}
|
||||
|
||||
object RemotedataUserAttributeCaseClasses extends RemotedataUserAttributeCaseClasses
|
||||
|
||||
Binary file not shown.
@ -23,9 +23,9 @@ class UserAttributesTest extends V400ServerSetup {
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations4_0_0.createCurrentUserAttribute))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.getCurrentUserAttributes))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.updateCurrentUserAttribute))
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations4_0_0.createMyPersonalUserAttribute))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.getMyPersonalUserAttributes))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.updateMyPersonalUserAttribute))
|
||||
|
||||
|
||||
lazy val bankId = testBankId1.value
|
||||
|
||||
174
obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala
Normal file
174
obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala
Normal file
@ -0,0 +1,174 @@
|
||||
package code.api.v5_1_0
|
||||
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.v4_0_0.UsersJsonV400
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import net.liftweb.json.Serialization.write
|
||||
import org.scalatest.Tag
|
||||
|
||||
|
||||
class UserAttributesTest extends V510ServerSetup {
|
||||
/**
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.createNonPersonalUserAttribute))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteNonPersonalUserAttribute))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getNonPersonalUserAttributes))
|
||||
|
||||
|
||||
lazy val bankId = testBankId1.value
|
||||
lazy val accountId = testAccountId1.value
|
||||
lazy val batteryLevel = "BATTERY_LEVEL"
|
||||
lazy val postUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV510.copy(name = batteryLevel)
|
||||
lazy val putUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV510.copy(name = "ROLE_2")
|
||||
|
||||
feature(s"test $ApiEndpoint1 $ApiEndpoint2 $ApiEndpoint3 version $VersionOfApi - Unauthorized access") {
|
||||
scenario(s"We will call the end $ApiEndpoint1 without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "users" /"testUserId"/ "non-personal" / "attributes").POST
|
||||
val response510 = makePostRequest(request510, write(postUserAttributeJsonV510))
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
|
||||
scenario(s"We will call the $ApiEndpoint2 without user credentials", ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "users" /"testUserId" / "non-personal" /"attributes"/"testUserAttributeId").DELETE
|
||||
val response510 = makeDeleteRequest(request510)
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
|
||||
scenario(s"We will call the $ApiEndpoint3 without user credentials", ApiEndpoint3, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "users" /"testUserId" / "non-personal" /"attributes").GET
|
||||
val response510 = makeGetRequest(request510)
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1 $ApiEndpoint2 $ApiEndpoint3 version $VersionOfApi - authorized access") {
|
||||
scenario(s"We will call the $ApiEndpoint1 $ApiEndpoint2 $ApiEndpoint3 with user credentials", ApiEndpoint1,
|
||||
ApiEndpoint2, ApiEndpoint3,VersionOfApi) {
|
||||
When("We make a request v5.1.0, we need to prepare the roles and users")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetAnyUser.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanCreateNonPersonalUserAttribute.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteNonPersonalUserAttribute.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetNonPersonalUserAttributes.toString)
|
||||
|
||||
val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1)
|
||||
val responseGetUsers = makeGetRequest(requestGetUsers)
|
||||
val userIds = responseGetUsers.body.extract[UsersJsonV400].users.map(_.user_id)
|
||||
val userId = userIds(scala.util.Random.nextInt(userIds.size))
|
||||
|
||||
val request510 = (v5_1_0_Request / "users"/ userId / "non-personal" /"attributes").POST <@ (user1)
|
||||
val response510 = makePostRequest(request510, write(postUserAttributeJsonV510))
|
||||
Then("We should get a 201")
|
||||
response510.code should equal(201)
|
||||
val jsonResponse = response510.body.extract[UserAttributeResponseJsonV510]
|
||||
jsonResponse.is_personal shouldBe(false)
|
||||
jsonResponse.name shouldBe(batteryLevel)
|
||||
val userAttributeId = jsonResponse.user_attribute_id
|
||||
|
||||
{
|
||||
val request510 = (v5_1_0_Request / "users" / userId / "non-personal" /"attributes").GET <@ (user1)
|
||||
val response510 = makeGetRequest(request510)
|
||||
Then("We should get a 200")
|
||||
response510.code should equal(200)
|
||||
val jsonResponse = response510.body.extract[UserAttributesResponseJsonV510]
|
||||
jsonResponse.user_attributes.length shouldBe (1)
|
||||
jsonResponse.user_attributes.head.name shouldBe (batteryLevel)
|
||||
jsonResponse.user_attributes.head.user_attribute_id shouldBe (userAttributeId)
|
||||
}
|
||||
val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"non-personal"/"attributes"/userAttributeId).DELETE <@ (user1)
|
||||
val responseDeleteUserAttribute = makeDeleteRequest(requestDeleteUserAttribute)
|
||||
Then("We should get a 204")
|
||||
responseDeleteUserAttribute.code should equal(204)
|
||||
|
||||
Then("We delete it again, we should get the can not find error")
|
||||
val responseDeleteUserAttributeAgain = makeDeleteRequest(requestDeleteUserAttribute)
|
||||
Then("We should get a 400")
|
||||
responseDeleteUserAttributeAgain.code should equal(400)
|
||||
responseDeleteUserAttributeAgain.body.extract[ErrorMessage].message contains (UserAttributeNotFound) shouldBe( true)
|
||||
|
||||
|
||||
{
|
||||
val request510 = (v5_1_0_Request / "users" / userId / "non-personal" /"attributes").GET <@ (user1)
|
||||
val response510 = makeGetRequest(request510)
|
||||
Then("We should get a 200")
|
||||
response510.code should equal(200)
|
||||
val jsonResponse = response510.body.extract[UserAttributesResponseJsonV510]
|
||||
jsonResponse.user_attributes.length shouldBe (0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scenario(s"We will call the $ApiEndpoint1 with user credentials, but missing roles", ApiEndpoint1, ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0, we need to prepare the roles and users")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetAnyUser.toString)
|
||||
|
||||
val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1)
|
||||
val responseGetUsers = makeGetRequest(requestGetUsers)
|
||||
val userIds = responseGetUsers.body.extract[UsersJsonV400].users.map(_.user_id)
|
||||
val userId = userIds(scala.util.Random.nextInt(userIds.size))
|
||||
|
||||
val request510 = (v5_1_0_Request / "users" / userId / "non-personal" /"attributes").POST <@ (user1)
|
||||
val response510 = makePostRequest(request510, write(postUserAttributeJsonV510))
|
||||
Then("We should get a 403")
|
||||
response510.code should equal(403)
|
||||
response510.body.extract[ErrorMessage].message contains (UserHasMissingRoles) shouldBe (true)
|
||||
response510.body.extract[ErrorMessage].message contains (ApiRole.CanCreateNonPersonalUserAttribute.toString()) shouldBe (true)
|
||||
}
|
||||
|
||||
scenario(s"We will call the $ApiEndpoint2 with user credentials, but missing roles", ApiEndpoint1, ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0, we need to prepare the roles and users")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetAnyUser.toString)
|
||||
|
||||
val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1)
|
||||
val responseGetUsers = makeGetRequest(requestGetUsers)
|
||||
val userIds = responseGetUsers.body.extract[UsersJsonV400].users.map(_.user_id)
|
||||
val userId = userIds(scala.util.Random.nextInt(userIds.size))
|
||||
|
||||
val request510 = (v5_1_0_Request / "users" / userId / "non-personal" /"attributes" / "attributeId").DELETE <@ (user1)
|
||||
val response510 = makeDeleteRequest(request510)
|
||||
Then("We should get a 403")
|
||||
response510.code should equal(403)
|
||||
response510.body.extract[ErrorMessage].message contains (UserHasMissingRoles) shouldBe (true)
|
||||
response510.body.extract[ErrorMessage].message contains (ApiRole.CanDeleteNonPersonalUserAttribute.toString()) shouldBe (true)
|
||||
}
|
||||
|
||||
scenario(s"We will call the $ApiEndpoint3 with user credentials, but missing roles", ApiEndpoint1, ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0, we need to prepare the roles and users")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetAnyUser.toString)
|
||||
|
||||
val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1)
|
||||
val responseGetUsers = makeGetRequest(requestGetUsers)
|
||||
val userIds = responseGetUsers.body.extract[UsersJsonV400].users.map(_.user_id)
|
||||
val userId = userIds(scala.util.Random.nextInt(userIds.size))
|
||||
|
||||
val request510 = (v5_1_0_Request / "users" / userId / "non-personal" /"attributes" ).GET <@ (user1)
|
||||
val response510 = makeGetRequest(request510)
|
||||
Then("We should get a 403")
|
||||
response510.code should equal(403)
|
||||
response510.body.extract[ErrorMessage].message contains (UserHasMissingRoles) shouldBe (true)
|
||||
response510.body.extract[ErrorMessage].message contains (ApiRole.CanGetNonPersonalUserAttributes.toString()) shouldBe (true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -103,6 +103,7 @@ trait UserAttributeTrait {
|
||||
def attributeType: UserAttributeType.Value
|
||||
def value: String
|
||||
def insertDate: Date
|
||||
def isPersonal: Boolean
|
||||
}
|
||||
|
||||
trait AccountAttribute {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user