From eed03ffab630181bab1738cd1581b5b18e9d093f Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 22 May 2023 17:42:54 +0800 Subject: [PATCH 01/15] refactor/changed the length of UserAttribute.name field --- .../code/api/util/migration/Migration.scala | 8 +++ ...rationOfUserAttributeNameFieldLength.scala | 62 +++++++++++++++++++ .../code/users/MappedUserAttribute.scala | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 obp-api/src/main/scala/code/api/util/migration/MigrationOfUserAttributeNameFieldLength.scala diff --git a/obp-api/src/main/scala/code/api/util/migration/Migration.scala b/obp-api/src/main/scala/code/api/util/migration/Migration.scala index 1b7efd691..1038cd97c 100644 --- a/obp-api/src/main/scala/code/api/util/migration/Migration.scala +++ b/obp-api/src/main/scala/code/api/util/migration/Migration.scala @@ -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.") diff --git a/obp-api/src/main/scala/code/api/util/migration/MigrationOfUserAttributeNameFieldLength.scala b/obp-api/src/main/scala/code/api/util/migration/MigrationOfUserAttributeNameFieldLength.scala new file mode 100644 index 000000000..7a8f0e3bc --- /dev/null +++ b/obp-api/src/main/scala/code/api/util/migration/MigrationOfUserAttributeNameFieldLength.scala @@ -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 + } + } +} \ No newline at end of file diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 6b281c10d..427fd4d29 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -65,7 +65,7 @@ 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) From f77e9f41a5a8ad7ecb4004ec2d711bd96335aede Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 23 May 2023 15:50:26 +0800 Subject: [PATCH 02/15] feature/OBPv510 added createUserAttribute endpoint --- .../main/scala/code/api/util/ApiRole.scala | 3 + .../scala/code/api/v5_1_0/APIMethods510.scala | 60 +++++++++++-- .../code/api/v5_1_0/UserAttributesTest.scala | 89 +++++++++++++++++++ 3 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index f9fabd6ad..9eb1463ab 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -403,6 +403,9 @@ object ApiRole { case class CanGetUsersWithAttributes (requiresBankId: Boolean = false) extends ApiRole lazy val canGetUsersWithAttributes = CanGetUsersWithAttributes() + + case class CanCreateUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canCreateUserAttribute = CanCreateUserAttribute() case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole lazy val canReadUserLockedStatus = CanReadUserLockedStatus() diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 008685988..1e9485579 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -13,7 +13,7 @@ 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.consent.Consents import code.loginattempts.LoginAttempt @@ -27,7 +27,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 @@ -113,9 +113,59 @@ trait APIMethods510 { (JSONFactory400.createApiCollectionsJsonV400(apiCollections), HttpCode.`200`(callContext)) } } - } - - + } + staticResourceDocs += ResourceDoc( + createUserAttribute, + implementedInApiVersion, + nameOf(createUserAttribute), + "POST", + "/users/USER_ID/attributes", + "Create User Attribute for the user", + s""" Create User Attribute for the user + | + |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" + | + |${authenticationRequiredMessage(true)} + | + |""", + userAttributeJsonV400, + userAttributeResponseJson, + List( + $UserNotLoggedIn, + InvalidJsonFormat, + UnknownError + ), + List(apiTagUser, apiTagNewStyle), + Some(List(canCreateUserAttribute)) + ) + + lazy val createUserAttribute: OBPEndpoint = { + case "users" :: userId :: "attributes" :: Nil JsonPost json -> _ => { + cc => + val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 " + for { + (attributes, callContext) <- NewStyle.function.getUserAttributes(userId, cc.callContext) + postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { + json.extract[UserAttributeJsonV400] + } + 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( + userId, + None, + postedData.name, + userAttributeType, + postedData.value, + callContext) + } yield { + (JSONFactory400.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext)) + } + } + } + staticResourceDocs += ResourceDoc( customViewNamesCheck, implementedInApiVersion, diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala new file mode 100644 index 000000000..c8d661eac --- /dev/null +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -0,0 +1,89 @@ +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.ApiRole.CanCreateUserAttribute +import code.api.util.ErrorMessages._ +import code.api.v4_0_0.{UserAttributeResponseJsonV400, 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.common.Box +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.createUserAttribute)) + + + lazy val bankId = testBankId1.value + lazy val accountId = testAccountId1.value + lazy val batteryLevel = "BATTERY_LEVEL" + lazy val postUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV400.copy(name = batteryLevel) + lazy val putUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV400.copy(name = "ROLE_2") + + + + feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") { + scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "users" /"testuserId"/ "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) + } + } + + feature(s"test $ApiEndpoint1 version $VersionOfApi - authorized access") { + scenario("We will call the endpoint with user credentials, but missing role", ApiEndpoint1, 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.CanCreateUserAttribute.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 / "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[UserAttributeResponseJsonV400] + jsonResponse.name should be(batteryLevel) + } + + scenario("We will call the endpoint with user credentials, but missing roles", ApiEndpoint1, 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 / "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.CanCreateUserAttribute.toString()) shouldBe (true) + } + } + +} From 1a4eefaf9d1613dce70f043c37d8a231b297fd8c Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 23 May 2023 17:21:04 +0800 Subject: [PATCH 03/15] feature/OBPv510 added deleteUserAttribute endpoint --- .../main/scala/code/api/util/ApiRole.scala | 3 + .../scala/code/api/v5_1_0/APIMethods510.scala | 47 ++++++++++++++- .../scala/code/bankconnectors/Connector.scala | 5 ++ .../bankconnectors/LocalMappedConnector.scala | 3 + .../remotedata/RemotedataUserAttribute.scala | 3 + .../code/users/MappedUserAttribute.scala | 13 ++++- .../code/users/UserAttributeProvider.scala | 2 + .../code/api/v5_1_0/UserAttributesTest.scala | 58 +++++++++++++++---- 8 files changed, 121 insertions(+), 13 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 9eb1463ab..72033abd7 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -406,6 +406,9 @@ object ApiRole { case class CanCreateUserAttribute (requiresBankId: Boolean = false) extends ApiRole lazy val canCreateUserAttribute = CanCreateUserAttribute() + + case class CanDeleteUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canDeleteUserAttribute = CanDeleteUserAttribute() case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole lazy val canReadUserLockedStatus = CanReadUserLockedStatus() diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 1e9485579..3da4fc675 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -15,6 +15,7 @@ import code.api.v3_1_0.ConsentJsonV310 import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson 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 @@ -132,6 +133,7 @@ trait APIMethods510 { userAttributeResponseJson, List( $UserNotLoggedIn, + UserHasMissingRoles, InvalidJsonFormat, UnknownError ), @@ -144,7 +146,7 @@ trait APIMethods510 { cc => val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 " for { - (attributes, callContext) <- NewStyle.function.getUserAttributes(userId, cc.callContext) + (user, callContext) <- NewStyle.function.getUserByUserId(userId, cc.callContext) postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { json.extract[UserAttributeJsonV400] } @@ -154,7 +156,7 @@ trait APIMethods510 { UserAttributeType.withName(postedData.`type`) } (userAttribute, callContext) <- NewStyle.function.createOrUpdateUserAttribute( - userId, + user.userId, None, postedData.name, userAttributeType, @@ -165,7 +167,48 @@ trait APIMethods510 { } } } + + resourceDocs += ResourceDoc( + deleteUserAttribute, + implementedInApiVersion, + nameOf(deleteUserAttribute), + "DELETE", + "/users/USER_ID/attributes/USER_ATTRIBUTE_ID", + "Delete User Attribute", + s"""Delete the 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(canDeleteUserAttribute))) + lazy val deleteUserAttribute: OBPEndpoint = { + case "users" :: userId :: "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)) + } + } + } + + staticResourceDocs += ResourceDoc( customViewNamesCheck, implementedInApiVersion, diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 0d9e85a3c..2a2e8ec69 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -2272,6 +2272,11 @@ trait Connector extends MdcLoggable { 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, diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 537d5632a..ba3f9edd0 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -4080,6 +4080,9 @@ object LocalMappedConnector extends Connector with MdcLoggable { 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], diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index 7c81b537a..5707f9688 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -22,6 +22,9 @@ object RemotedataUserAttribute extends ObpActorInit with UserAttributeProvider { 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, diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 427fd4d29..2c336d973 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -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 @@ -25,6 +26,16 @@ object MappedUserAttributeProvider extends UserAttributeProvider { 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], diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index e921ea5e9..1040a071b 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -39,6 +39,7 @@ trait UserAttributeProvider { def getUserAttributesByUser(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, @@ -49,6 +50,7 @@ trait UserAttributeProvider { class RemotedataUserAttributeCaseClasses { case class getUserAttributesByUser(userId: String) + case class deleteUserAttribute(userAttributeId: String) case class getUserAttributesByUsers(userIds: List[String]) case class createOrUpdateUserAttribute(userId: String, userAttributeId: Option[String], diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index c8d661eac..ad87e894f 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -11,7 +11,6 @@ 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.common.Box import net.liftweb.json.Serialization.write import org.scalatest.Tag @@ -26,6 +25,7 @@ class UserAttributesTest extends V510ServerSetup { */ object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString) object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.createUserAttribute)) + object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteUserAttribute)) lazy val bankId = testBankId1.value @@ -36,24 +36,32 @@ class UserAttributesTest extends V510ServerSetup { - feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") { - scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + feature(s"test $ApiEndpoint1 $ApiEndpoint2 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"/ "attributes").POST + val request510 = (v5_1_0_Request / "users" /"testUserId"/ "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", ApiEndpoint1, VersionOfApi) { + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "users" /"testUserId"/ "attributes"/"testUserAttributeId").POST + val response510 = makeDeleteRequest(request510) + Then("We should get a 401") + response510.code should equal(401) + response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) + } } - feature(s"test $ApiEndpoint1 version $VersionOfApi - authorized access") { - scenario("We will call the endpoint with user credentials, but missing role", ApiEndpoint1, VersionOfApi) { + feature(s"test $ApiEndpoint1 $ApiEndpoint2 version $VersionOfApi - authorized access") { + scenario(s"We will call the $ApiEndpoint1 $ApiEndpoint2 with user credentials", 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) Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanCreateUserAttribute.toString) - - + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteUserAttribute.toString) val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1) val responseGetUsers = makeGetRequest(requestGetUsers) @@ -65,10 +73,23 @@ class UserAttributesTest extends V510ServerSetup { Then("We should get a 201") response510.code should equal(201) val jsonResponse = response510.body.extract[UserAttributeResponseJsonV400] - jsonResponse.name should be(batteryLevel) + val userAttributeId = jsonResponse.user_attribute_id + + + val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"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) + } - scenario("We will call the endpoint with user credentials, but missing roles", ApiEndpoint1, VersionOfApi) { + 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) @@ -84,6 +105,23 @@ class UserAttributesTest extends V510ServerSetup { response510.body.extract[ErrorMessage].message contains (UserHasMissingRoles) shouldBe (true) response510.body.extract[ErrorMessage].message contains (ApiRole.CanCreateUserAttribute.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 / "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.CanDeleteUserAttribute.toString()) shouldBe (true) + } } } From 51daabd844f34d903c83964fa801dd68e584c394 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 23 May 2023 19:46:35 +0800 Subject: [PATCH 04/15] refactor/added the props values to InvalidChallengeAnswer --- obp-api/src/main/scala/code/api/util/ErrorMessages.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index 30518cd25..deb679774 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -551,9 +551,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(${transactionRequestChallengeTtl} seconds)." + + s"Or you've used up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts})." + "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 " From 9e78dc115a5d00d03547b98cff2e82f6523dc3b3 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 23 May 2023 20:52:58 +0800 Subject: [PATCH 05/15] refactor/added the isPersonal to create endpoints --- .../main/scala/code/api/util/NewStyle.scala | 2 + .../scala/code/api/v4_0_0/APIMethods400.scala | 47 ++++++++++--------- .../scala/code/api/v5_1_0/APIMethods510.scala | 10 ++-- .../code/api/v5_1_0/JSONFactory5.1.0.scala | 22 +++++++++ .../scala/code/bankconnectors/Connector.scala | 1 + .../bankconnectors/LocalMappedConnector.scala | 4 +- .../remotedata/RemotedataUserAttribute.scala | 5 +- .../RemotedataUserAttributeActor.scala | 10 ++-- .../code/users/MappedUserAttribute.scala | 9 +++- .../code/users/UserAttributeProvider.scala | 6 ++- .../code/api/v4_0_0/UserAttributesTest.scala | 4 +- .../code/api/v5_1_0/UserAttributesTest.scala | 7 +-- .../commons/model/CommonModelTrait.scala | 1 + 13 files changed, 87 insertions(+), 41 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 17920b96a..b285837c0 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1901,6 +1901,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 +1910,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) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 39e3126f0..18a86f5b6 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -8739,13 +8739,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, @@ -8758,7 +8758,7 @@ trait APIMethods400 { List(apiTagUser, apiTagNewStyle) ) - lazy val getCurrentUserAttributes: OBPEndpoint = { + lazy val getMyPersonalUserAttributes: OBPEndpoint = { case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc => for { @@ -8805,15 +8805,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)} | @@ -8828,18 +8828,17 @@ trait APIMethods400 { List(apiTagUser, apiTagNewStyle), 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( @@ -8848,7 +8847,8 @@ trait APIMethods400 { postedData.name, userAttributeType, postedData.value, - callContext + true, + cc.callContext ) } yield { (JSONFactory400.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext)) @@ -8862,8 +8862,8 @@ trait APIMethods400 { nameOf(updateCurrentUserAttribute), "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" | @@ -8883,7 +8883,7 @@ trait APIMethods400 { lazy val updateCurrentUserAttribute : OBPEndpoint = { case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut 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) failMsg = s"$UserAttributeNotFound" @@ -8891,10 +8891,10 @@ trait APIMethods400 { attributes.exists(_.userAttributeId == userAttributeId) } postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { - json.extract[TransactionAttributeJsonV400] + 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`) } @@ -8904,6 +8904,7 @@ trait APIMethods400 { postedData.name, userAttributeType, postedData.value, + true, callContext ) } yield { diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 3da4fc675..5046b11bb 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -121,8 +121,8 @@ trait APIMethods510 { nameOf(createUserAttribute), "POST", "/users/USER_ID/attributes", - "Create User Attribute for the user", - s""" Create User Attribute for the user + "Create User Attribute", + s""" Create User Attribute | |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" | @@ -161,9 +161,11 @@ trait APIMethods510 { postedData.name, userAttributeType, postedData.value, - callContext) + false, + callContext + ) } yield { - (JSONFactory400.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext)) + (JSONFactory510.createUserAttributeJson(userAttribute), HttpCode.`201`(callContext)) } } } diff --git a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala index ec2529ad3..c3a3eab94 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala @@ -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 @@ -155,6 +157,16 @@ case class AtmAttributeResponseJsonV510( ) case class AtmAttributesResponseJsonV510(atm_attributes: List[AtmAttributeResponseJsonV510]) +case class UserAttributeResponseJsonV510( + user_attribute_id: String, + name: String, + `type`: String, + value: String, + insert_date: Date, + is_personal: Boolean +) + + object JSONFactory510 { @@ -372,6 +384,16 @@ 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 + ) + } } diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 2a2e8ec69..e4160e1d3 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -2269,6 +2269,7 @@ trait Connector extends MdcLoggable { name: String, attributeType: UserAttributeType.Value, value: String, + isPersonal: Boolean, callContext: Option[CallContext] ): OBPReturnType[Box[UserAttribute]] = Future{(Failure(setUnimplementedError), callContext)} diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index ba3f9edd0..1484bb208 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -4089,6 +4089,7 @@ object LocalMappedConnector extends Connector with MdcLoggable { name: String, attributeType: UserAttributeType.Value, value: String, + isPersonal: Boolean, callContext: Option[CallContext] ): OBPReturnType[Box[UserAttribute]] = { UserAttributeProvider.userAttributeProvider.vend.createOrUpdateUserAttribute( @@ -4096,7 +4097,8 @@ object LocalMappedConnector extends Connector with MdcLoggable { userAttributeId: Option[String], name: String, attributeType: UserAttributeType.Value, - value: String + value: String, + isPersonal: Boolean ) map { (_, callContext) } diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index 5707f9688..eb78d96fb 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -29,7 +29,8 @@ object RemotedataUserAttribute extends ObpActorInit with UserAttributeProvider { 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]] } diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttributeActor.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttributeActor.scala index 9faacc237..312902aae 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttributeActor.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttributeActor.scala @@ -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) } diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 2c336d973..002cb3132 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -41,7 +41,8 @@ object MappedUserAttributeProvider extends UserAttributeProvider { 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 { @@ -51,6 +52,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 @@ -63,6 +65,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider { .Name(name) .Type(attributeType.toString()) .`Value`(value) + .IsPersonal(isPersonal) .saveMe() } } @@ -79,6 +82,9 @@ class UserAttribute extends UserAttributeTrait with LongKeyedMapper[UserAttribut 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 @@ -86,6 +92,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] { diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index 1040a071b..c386b7514 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -44,7 +44,8 @@ trait UserAttributeProvider { userAttributeId: Option[String], name: String, attributeType: UserAttributeType.Value, - value: String): Future[Box[UserAttribute]] + value: String, + isPersonal: Boolean): Future[Box[UserAttribute]] // End of Trait } @@ -56,7 +57,8 @@ class RemotedataUserAttributeCaseClasses { userAttributeId: Option[String], name: String, attributeType: UserAttributeType.Value, - value: String) + value: String, + isPersonal: Boolean) } object RemotedataUserAttributeCaseClasses extends RemotedataUserAttributeCaseClasses diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala index 46f1067f2..27e7eb172 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala @@ -23,8 +23,8 @@ 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 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.updateCurrentUserAttribute)) diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index ad87e894f..dd7095989 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -3,9 +3,8 @@ 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.ApiRole.CanCreateUserAttribute import code.api.util.ErrorMessages._ -import code.api.v4_0_0.{UserAttributeResponseJsonV400, UsersJsonV400} +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 @@ -72,7 +71,9 @@ class UserAttributesTest extends V510ServerSetup { val response510 = makePostRequest(request510, write(postUserAttributeJsonV510)) Then("We should get a 201") response510.code should equal(201) - val jsonResponse = response510.body.extract[UserAttributeResponseJsonV400] + val jsonResponse = response510.body.extract[UserAttributeResponseJsonV510] + jsonResponse.is_personal shouldBe(false) + jsonResponse.name shouldBe(batteryLevel) val userAttributeId = jsonResponse.user_attribute_id diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala index 63da94958..b95706620 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala @@ -103,6 +103,7 @@ trait UserAttributeTrait { def attributeType: UserAttributeType.Value def value: String def insertDate: Date + def isPersonal: Boolean } trait AccountAttribute { From 718adb5838010d97d1f3d18f3c8a09cd00675430 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 23 May 2023 23:31:53 +0800 Subject: [PATCH 06/15] feature/OBPv510 added new endpoint getUserAttributes and added isPersonal to create endpoint --- .../SwaggerDefinitionsJSON.scala | 16 +++++ .../main/scala/code/api/util/ApiRole.scala | 3 + .../scala/code/api/util/ExampleValue.scala | 7 +- .../main/scala/code/api/util/NewStyle.scala | 8 +++ .../scala/code/api/v4_0_0/APIMethods400.scala | 17 +++-- .../scala/code/api/v5_1_0/APIMethods510.scala | 50 ++++++++++++-- .../code/api/v5_1_0/JSONFactory5.1.0.scala | 18 ++++- .../scala/code/bankconnectors/Connector.scala | 3 + .../bankconnectors/LocalMappedConnector.scala | 4 ++ .../remotedata/RemotedataUserAttribute.scala | 3 + .../code/users/MappedUserAttribute.scala | 8 +++ .../code/users/UserAttributeProvider.scala | 2 + .../code/api/v4_0_0/UserAttributesTest.scala | 2 +- .../code/api/v5_1_0/UserAttributesTest.scala | 66 ++++++++++++++++--- 14 files changed, 178 insertions(+), 29 deletions(-) diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index 0e60d82ef..ba509edfc 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -5325,6 +5325,22 @@ object SwaggerDefinitionsJSON { attributes = Some(List(atmAttributeResponseJsonV510)) ) + + val userAttributeJsonV510 = UserAttributeJsonV510( + name = userAttributeNameExample.value, + `type` = userAttributeTypeExample.value, + value = userAttributeValueExample.value, + is_personal = userAttributeIsPersonalExample.value.toBoolean + ) + + 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 atmsJsonV510 = AtmsJsonV510( atms = List(atmJsonV510) diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 72033abd7..d1e2b7032 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -407,6 +407,9 @@ object ApiRole { case class CanCreateUserAttribute (requiresBankId: Boolean = false) extends ApiRole lazy val canCreateUserAttribute = CanCreateUserAttribute() + case class CanGetUserAttributes (requiresBankId: Boolean = false) extends ApiRole + lazy val canGetUserAttributes = CanGetUserAttributes() + case class CanDeleteUserAttribute (requiresBankId: Boolean = false) extends ApiRole lazy val canDeleteUserAttribute = CanDeleteUserAttribute() diff --git a/obp-api/src/main/scala/code/api/util/ExampleValue.scala b/obp-api/src/main/scala/code/api/util/ExampleValue.scala index 519718ac7..026816edb 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -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) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index b285837c0..83228f41a 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1888,6 +1888,14 @@ object NewStyle extends MdcLoggable{ } } + def getMyPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[List[UserAttribute]] = { + Connector.connector.vend.getMyPersonalUserAttributes( + 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] diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 18a86f5b6..8b9c99d2a 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -8762,7 +8762,7 @@ trait APIMethods400 { case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc => for { - (attributes, callContext) <- NewStyle.function.getUserAttributes(cc.userId, cc.callContext) + (attributes, callContext) <- NewStyle.function.getMyPersonalUserAttributes(cc.userId, cc.callContext) } yield { (JSONFactory400.createUserAttributesJson(attributes), HttpCode.`200`(callContext)) } @@ -8776,7 +8776,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)} @@ -8796,7 +8796,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)) } @@ -8857,9 +8857,9 @@ trait APIMethods400 { } staticResourceDocs += ResourceDoc( - updateCurrentUserAttribute, + updateMyPersonalUserAttribute, implementedInApiVersion, - nameOf(updateCurrentUserAttribute), + nameOf(updateMyPersonalUserAttribute), "PUT", "/my/user/attributes/USER_ATTRIBUTE_ID", "Update My Personal User Attribute", @@ -8880,17 +8880,16 @@ trait APIMethods400 { List(apiTagUser, apiTagNewStyle), 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 $UserAttributeJsonV400 " for { - (attributes, callContext) <- NewStyle.function.getUserAttributes(cc.userId, cc.callContext) + (attributes, callContext) <- NewStyle.function.getMyPersonalUserAttributes(cc.userId, cc.callContext) failMsg = s"$UserAttributeNotFound" _ <- NewStyle.function.tryons(failMsg, 400, callContext) { attributes.exists(_.userAttributeId == userAttributeId) } - postedData <- NewStyle.function.tryons(failMsg, 400, callContext) { + 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: " + diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 5046b11bb..e6d70a5e2 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -129,8 +129,8 @@ trait APIMethods510 { |${authenticationRequiredMessage(true)} | |""", - userAttributeJsonV400, - userAttributeResponseJson, + userAttributeJsonV510, + userAttributeResponseJsonV510, List( $UserNotLoggedIn, UserHasMissingRoles, @@ -144,11 +144,11 @@ trait APIMethods510 { lazy val createUserAttribute: OBPEndpoint = { case "users" :: userId :: "attributes" :: Nil JsonPost json -> _ => { cc => - val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV400 " + 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[UserAttributeJsonV400] + 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)" @@ -161,7 +161,7 @@ trait APIMethods510 { postedData.name, userAttributeType, postedData.value, - false, + postedData.is_personal, callContext ) } yield { @@ -210,6 +210,46 @@ trait APIMethods510 { } } + resourceDocs += ResourceDoc( + getUserAttributes, + implementedInApiVersion, + nameOf(getUserAttributes), + "GET", + "/users/USER_ID/attributes", + "Get User Attributes", + s"""Get User Attribute for a user specified by USER_ID + | + |${authenticationRequiredMessage(true)} + |""".stripMargin, + EmptyBody, + EmptyBody, + List( + UserNotLoggedIn, + UserHasMissingRoles, + InvalidConnectorResponse, + UnknownError + ), + List(apiTagUser, apiTagNewStyle), + Some(List(canGetUserAttributes))) + + lazy val getUserAttributes: OBPEndpoint = { + case "users" :: userId :: "attributes" :: Nil JsonGet _ => { + cc => + for { + (_, callContext) <- authenticatedAccess(cc) + (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext) + (userAttributes,callContext) <- Connector.connector.vend.getUserAttributes( + user.userId, + callContext, + ) map { + i => (connectorEmptyResponse (i._1, callContext), i._2) + } + } yield { + (JSONFactory510.createUserAttributesJson(userAttributes), HttpCode.`200`(callContext)) + } + } + } + staticResourceDocs += ResourceDoc( customViewNamesCheck, diff --git a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala index c3a3eab94..92cef5291 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala @@ -162,10 +162,21 @@ case class UserAttributeResponseJsonV510( name: String, `type`: String, value: String, - insert_date: Date, + is_personal: Boolean, + insert_date: Date +) + +case class UserAttributeJsonV510( + name: String, + `type`: String, + value: String, is_personal: Boolean ) +case class UserAttributesResponseJsonV510( + user_attributes: List[UserAttributeResponseJsonV510] +) + object JSONFactory510 { @@ -394,6 +405,9 @@ object JSONFactory510 { is_personal = userAttribute.isPersonal ) } - + + def createUserAttributesJson(userAttribute: List[UserAttribute]): UserAttributesResponseJsonV510 = { + UserAttributesResponseJsonV510(userAttribute.map(createUserAttributeJson)) + } } diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index e4160e1d3..33b08924e 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -2260,6 +2260,9 @@ trait Connector extends MdcLoggable { def getUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = Future{(Failure(setUnimplementedError), callContext)} + def getMyPersonalUserAttributes(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)} diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 1484bb208..de39947eb 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -4077,6 +4077,10 @@ 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 getMyPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = { + UserAttributeProvider.userAttributeProvider.vend.getMyPersonalUserAttributes(userId: String) map {(_, callContext)} + } override def getUserAttributesByUsers(userIds: List[String], callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = { UserAttributeProvider.userAttributeProvider.vend.getUserAttributesByUsers(userIds) map {(_, callContext)} } diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index eb78d96fb..64a1c10a6 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -19,6 +19,9 @@ 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 getMyPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = + (actor ? cc.getMyPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] + override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] = (actor ? cc.getUserAttributesByUsers(userIds)).mapTo[Box[List[UserAttribute]]] diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 002cb3132..997bf6cc7 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -20,6 +20,14 @@ object MappedUserAttributeProvider extends UserAttributeProvider { UserAttribute.findAll(By(UserAttribute.UserId, userId)) ) } + override def getMyPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { + tryo( + UserAttribute.findAll( + By(UserAttribute.UserId, userId), + By(UserAttribute.IsPersonal, true) + ) + ) + } override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] = Future { tryo( diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index c386b7514..75d2e42bb 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -38,6 +38,7 @@ trait UserAttributeProvider { private val logger = Logger(classOf[UserAttributeProvider]) def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]] + def getMyPersonalUserAttributes(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, @@ -51,6 +52,7 @@ trait UserAttributeProvider { class RemotedataUserAttributeCaseClasses { case class getUserAttributesByUser(userId: String) + case class getMyPersonalUserAttributes(userId: String) case class deleteUserAttribute(userAttributeId: String) case class getUserAttributesByUsers(userIds: List[String]) case class createOrUpdateUserAttribute(userId: String, diff --git a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala index 27e7eb172..97e3fbfc2 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/UserAttributesTest.scala @@ -25,7 +25,7 @@ class UserAttributesTest extends V400ServerSetup { object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString) 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.updateCurrentUserAttribute)) + object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.updateMyPersonalUserAttribute)) lazy val bankId = testBankId1.value diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index dd7095989..afb561f12 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -25,17 +25,16 @@ class UserAttributesTest extends V510ServerSetup { object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString) object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.createUserAttribute)) object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteUserAttribute)) + object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getUserAttributes)) lazy val bankId = testBankId1.value lazy val accountId = testAccountId1.value lazy val batteryLevel = "BATTERY_LEVEL" - lazy val postUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV400.copy(name = batteryLevel) - lazy val putUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV400.copy(name = "ROLE_2") + lazy val postUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV510.copy(name = batteryLevel) + lazy val putUserAttributeJsonV510 = SwaggerDefinitionsJSON.userAttributeJsonV510.copy(name = "ROLE_2") - - - feature(s"test $ApiEndpoint1 $ApiEndpoint2 version $VersionOfApi - Unauthorized access") { + 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"/ "attributes").POST @@ -45,22 +44,33 @@ class UserAttributesTest extends V510ServerSetup { response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) } - scenario(s"We will call the $ApiEndpoint2 without user credentials", ApiEndpoint1, VersionOfApi) { + 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"/ "attributes"/"testUserAttributeId").POST + val request510 = (v5_1_0_Request / "users" /"testUserId"/ "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"/ "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 version $VersionOfApi - authorized access") { - scenario(s"We will call the $ApiEndpoint1 $ApiEndpoint2 with user credentials", ApiEndpoint1, ApiEndpoint2,VersionOfApi) { + 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.CanCreateUserAttribute.toString) Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteUserAttribute.toString) + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetUserAttributes.toString) val requestGetUsers = (v5_1_0_Request / "users").GET <@ (user1) val responseGetUsers = makeGetRequest(requestGetUsers) @@ -76,7 +86,16 @@ class UserAttributesTest extends V510ServerSetup { jsonResponse.name shouldBe(batteryLevel) val userAttributeId = jsonResponse.user_attribute_id - + { + val request510 = (v5_1_0_Request / "users" / userId / "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/"attributes"/userAttributeId).DELETE <@ (user1) val responseDeleteUserAttribute = makeDeleteRequest(requestDeleteUserAttribute) Then("We should get a 204") @@ -87,6 +106,16 @@ class UserAttributesTest extends V510ServerSetup { 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 / "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) + } } @@ -123,6 +152,23 @@ class UserAttributesTest extends V510ServerSetup { response510.body.extract[ErrorMessage].message contains (UserHasMissingRoles) shouldBe (true) response510.body.extract[ErrorMessage].message contains (ApiRole.CanDeleteUserAttribute.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 / "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.CanGetUserAttributes.toString()) shouldBe (true) + } } } From 82903b525b9203de8dc076646c6f35a2138e07fd Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 24 May 2023 15:28:12 +0800 Subject: [PATCH 07/15] tests/fixed the failed tests --- .../src/test/resources/frozen_type_meta_data | Bin 140748 -> 140757 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/obp-api/src/test/resources/frozen_type_meta_data b/obp-api/src/test/resources/frozen_type_meta_data index e02f9500f40ab32576723ede600d97350fd0bb2f..16e25bbbf355224f2406507e4e8ecc494ae1b150 100644 GIT binary patch delta 145 zcmX?en&awejt#~NoBb3XvP%0_2Ba1h=jSEngche3IhK?ZWhRxDq!yPjNKdx6ke=+W zW~(BbT$Gwvl8QrV34?rkYRTk-O46GbtLd_AeyhdAAtzf}kb+yw Date: Wed, 24 May 2023 16:37:56 +0800 Subject: [PATCH 08/15] refactor/tweaked the error message InvalidChallengeAnswer --- .../scala/code/api/util/ErrorMessages.scala | 4 ++-- .../src/main/scala/code/api/util/NewStyle.scala | 12 ++++++++++-- .../scala/code/api/v2_1_0/APIMethods210.scala | 5 ++++- .../scala/code/api/v4_0_0/APIMethods400.scala | 5 ++++- .../MappedChallengeProvider.scala | 17 ++++++++++++++--- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index deb679774..202cde0a1 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -552,8 +552,8 @@ object ErrorMessages { 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 = s"OBP-40016: Invalid Challenge Answer. Please specify a valid value for answer in Json body. " + - s"The challenge answer may be expired(${transactionRequestChallengeTtl} seconds)." + - s"Or you've used up your allowed attempts (${allowedAnswerTransactionRequestChallengeAttempts})." + + 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 " diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 83228f41a..43161b096 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -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) } } } diff --git a/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala b/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala index ef8457cae..5caa19dce 100644 --- a/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala +++ b/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala @@ -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) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 8b9c99d2a..6c709c01e 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -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 } diff --git a/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala b/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala index 629cdb3a2..0006d6f5e 100644 --- a/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala +++ b/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala @@ -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{ From 046d756412650a3e52d2c644410259461c4ee95c Mon Sep 17 00:00:00 2001 From: hongwei Date: Thu, 25 May 2023 21:16:59 +0800 Subject: [PATCH 09/15] refactor/added new method getNotPersonalUserAttributes and add isPersonal to getPersonalUserAttributes method --- .../src/main/scala/code/api/util/NewStyle.scala | 4 ++-- .../main/scala/code/api/v4_0_0/APIMethods400.scala | 4 ++-- .../main/scala/code/bankconnectors/Connector.scala | 2 +- .../code/bankconnectors/LocalMappedConnector.scala | 5 +++-- .../code/remotedata/RemotedataUserAttribute.scala | 7 +++++-- .../scala/code/users/MappedUserAttribute.scala | 14 ++++++++++++-- .../scala/code/users/UserAttributeProvider.scala | 6 ++++-- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 43161b096..c2043b386 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1896,8 +1896,8 @@ object NewStyle extends MdcLoggable{ } } - def getMyPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[List[UserAttribute]] = { - Connector.connector.vend.getMyPersonalUserAttributes( + 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) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 6c709c01e..d4191505e 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -8765,7 +8765,7 @@ trait APIMethods400 { case "my" :: "user" :: "attributes" :: Nil JsonGet _ => { cc => for { - (attributes, callContext) <- NewStyle.function.getMyPersonalUserAttributes(cc.userId, cc.callContext) + (attributes, callContext) <- NewStyle.function.getPersonalUserAttributes(cc.userId, cc.callContext) } yield { (JSONFactory400.createUserAttributesJson(attributes), HttpCode.`200`(callContext)) } @@ -8887,7 +8887,7 @@ trait APIMethods400 { case "my" :: "user" :: "attributes" :: userAttributeId :: Nil JsonPut json -> _=> { cc => for { - (attributes, callContext) <- NewStyle.function.getMyPersonalUserAttributes(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) diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 33b08924e..e480e4f4d 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -2260,7 +2260,7 @@ trait Connector extends MdcLoggable { def getUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = Future{(Failure(setUnimplementedError), callContext)} - def getMyPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = + def getPersonalUserAttributes(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]]] = diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index de39947eb..d3fa8095f 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -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) @@ -4078,8 +4079,8 @@ object LocalMappedConnector extends Connector with MdcLoggable { UserAttributeProvider.userAttributeProvider.vend.getUserAttributesByUser(userId: String) map {(_, callContext)} } - override def getMyPersonalUserAttributes(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAttribute]]] = { - UserAttributeProvider.userAttributeProvider.vend.getMyPersonalUserAttributes(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)} diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index 64a1c10a6..1b030f53a 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -19,8 +19,11 @@ 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 getMyPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = - (actor ? cc.getMyPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] + override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = + (actor ? cc.getPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] + + override def getNotPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = + (actor ? cc.getNotPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] = (actor ? cc.getUserAttributesByUsers(userIds)).mapTo[Box[List[UserAttribute]]] diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 997bf6cc7..1cf6a4969 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -20,11 +20,21 @@ object MappedUserAttributeProvider extends UserAttributeProvider { UserAttribute.findAll(By(UserAttribute.UserId, userId)) ) } - override def getMyPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { + override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { tryo( UserAttribute.findAll( By(UserAttribute.UserId, userId), - By(UserAttribute.IsPersonal, true) + By(UserAttribute.IsPersonal, true), + OrderBy(UserAttribute.createdAt, Descending) + ) + ) + } + override def getNotPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { + tryo( + UserAttribute.findAll( + By(UserAttribute.UserId, userId), + By(UserAttribute.IsPersonal, false), + OrderBy(UserAttribute.createdAt, Descending) ) ) } diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index 75d2e42bb..7260645be 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -38,7 +38,8 @@ trait UserAttributeProvider { private val logger = Logger(classOf[UserAttributeProvider]) def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]] - def getMyPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] + def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] + def getNotPersonalUserAttributes(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, @@ -52,7 +53,8 @@ trait UserAttributeProvider { class RemotedataUserAttributeCaseClasses { case class getUserAttributesByUser(userId: String) - case class getMyPersonalUserAttributes(userId: String) + case class getPersonalUserAttributes(userId: String) + case class getNotPersonalUserAttributes(userId: String) case class deleteUserAttribute(userAttributeId: String) case class getUserAttributesByUsers(userIds: List[String]) case class createOrUpdateUserAttribute(userId: String, From aa581d293447ea81209a8563dd03ccfabd12a453 Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 26 May 2023 20:42:29 +0800 Subject: [PATCH 10/15] refactor/rename getNotPersonalUserAttributes--> getNonePersonalUserAttributes --- .../main/scala/code/remotedata/RemotedataUserAttribute.scala | 4 ++-- obp-api/src/main/scala/code/users/MappedUserAttribute.scala | 2 +- obp-api/src/main/scala/code/users/UserAttributeProvider.scala | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index 1b030f53a..1641e73ae 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -22,8 +22,8 @@ object RemotedataUserAttribute extends ObpActorInit with UserAttributeProvider { override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = (actor ? cc.getPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] - override def getNotPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = - (actor ? cc.getNotPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] + override def getNonePersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = + (actor ? cc.getNonePersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] override def getUserAttributesByUsers(userIds: List[String]): Future[Box[List[UserAttribute]]] = (actor ? cc.getUserAttributesByUsers(userIds)).mapTo[Box[List[UserAttribute]]] diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 1cf6a4969..628e6204b 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -29,7 +29,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider { ) ) } - override def getNotPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { + override def getNonePersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { tryo( UserAttribute.findAll( By(UserAttribute.UserId, userId), diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index 7260645be..ab95e2e25 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -39,7 +39,7 @@ trait UserAttributeProvider { def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]] def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] - def getNotPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] + def getNonePersonalUserAttributes(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, @@ -54,7 +54,7 @@ trait UserAttributeProvider { class RemotedataUserAttributeCaseClasses { case class getUserAttributesByUser(userId: String) case class getPersonalUserAttributes(userId: String) - case class getNotPersonalUserAttributes(userId: String) + case class getNonePersonalUserAttributes(userId: String) case class deleteUserAttribute(userAttributeId: String) case class getUserAttributesByUsers(userIds: List[String]) case class createOrUpdateUserAttribute(userId: String, From dc5885ab78d204a011da1a27181673a45099c1a0 Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 26 May 2023 23:04:03 +0800 Subject: [PATCH 11/15] refactor/added the new method getBankAccountByRouting --- .../group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala | 2 +- obp-api/src/main/scala/code/api/util/NewStyle.scala | 4 ++-- .../main/scala/code/bankconnectors/Connector.scala | 3 ++- .../code/bankconnectors/LocalMappedConnector.scala | 11 ++++++++--- .../bankconnectors/akka/AkkaConnector_vDec2018.scala | 2 +- .../bankconnectors/rest/RestConnector_vMar2019.scala | 2 +- .../StoredProcedureConnector_vDec2019.scala | 2 +- .../src/main/scala/code/sandbox/OBPDataImport.scala | 2 +- 8 files changed, 17 insertions(+), 11 deletions(-) diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala index d8686484c..9c660b5bf 100644 --- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala +++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala @@ -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, diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index c2043b386..09f66ba0c 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -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) } } diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index e480e4f4d..e9c63239f 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -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) diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index d3fa8095f..6b203ff7e 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -760,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 @@ -776,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 { @@ -1786,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 => diff --git a/obp-api/src/main/scala/code/bankconnectors/akka/AkkaConnector_vDec2018.scala b/obp-api/src/main/scala/code/bankconnectors/akka/AkkaConnector_vDec2018.scala index f2afd131a..9e6ca7c2c 100644 --- a/obp-api/src/main/scala/code/bankconnectors/akka/AkkaConnector_vDec2018.scala +++ b/obp-api/src/main/scala/code/bankconnectors/akka/AkkaConnector_vDec2018.scala @@ -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 !! _) diff --git a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala index adb8dd156..401f389cd 100644 --- a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala @@ -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) diff --git a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala index d673c2539..9b9d87b96 100644 --- a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala @@ -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) diff --git a/obp-api/src/main/scala/code/sandbox/OBPDataImport.scala b/obp-api/src/main/scala/code/sandbox/OBPDataImport.scala index 4c42a36c5..e9d55dcbc 100644 --- a/obp-api/src/main/scala/code/sandbox/OBPDataImport.scala +++ b/obp-api/src/main/scala/code/sandbox/OBPDataImport.scala @@ -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) { From 088d208289b88ed78c05378308e6b92af0ce56f4 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 29 May 2023 18:40:36 +0800 Subject: [PATCH 12/15] feature/added the none personal the user attributes endpoints --- .../SwaggerDefinitionsJSON.scala | 3 +- .../main/scala/code/api/util/ApiRole.scala | 12 ++-- .../scala/code/api/v5_1_0/APIMethods510.scala | 56 +++++++++---------- .../code/api/v5_1_0/JSONFactory5.1.0.scala | 3 +- .../code/api/v5_1_0/UserAttributesTest.scala | 38 ++++++------- 5 files changed, 54 insertions(+), 58 deletions(-) diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index 6d2c80642..49c1f1947 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -5329,8 +5329,7 @@ object SwaggerDefinitionsJSON { val userAttributeJsonV510 = UserAttributeJsonV510( name = userAttributeNameExample.value, `type` = userAttributeTypeExample.value, - value = userAttributeValueExample.value, - is_personal = userAttributeIsPersonalExample.value.toBoolean + value = userAttributeValueExample.value ) val userAttributeResponseJsonV510 = UserAttributeResponseJsonV510( diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index d1e2b7032..18c3a357a 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -404,14 +404,14 @@ object ApiRole { case class CanGetUsersWithAttributes (requiresBankId: Boolean = false) extends ApiRole lazy val canGetUsersWithAttributes = CanGetUsersWithAttributes() - case class CanCreateUserAttribute (requiresBankId: Boolean = false) extends ApiRole - lazy val canCreateUserAttribute = CanCreateUserAttribute() + case class CanCreateNonePersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canCreateNonePersonalUserAttribute = CanCreateNonePersonalUserAttribute() - case class CanGetUserAttributes (requiresBankId: Boolean = false) extends ApiRole - lazy val canGetUserAttributes = CanGetUserAttributes() + case class CanGetNonePersonalUserAttributes (requiresBankId: Boolean = false) extends ApiRole + lazy val canGetNonePersonalUserAttributes = CanGetNonePersonalUserAttributes() - case class CanDeleteUserAttribute (requiresBankId: Boolean = false) extends ApiRole - lazy val canDeleteUserAttribute = CanDeleteUserAttribute() + case class CanDeleteNonePersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canDeleteNonePersonalUserAttribute = CanDeleteNonePersonalUserAttribute() case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole lazy val canReadUserLockedStatus = CanReadUserLockedStatus() diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index d98e3d478..3fbfd9f42 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -155,13 +155,13 @@ trait APIMethods510 { } } staticResourceDocs += ResourceDoc( - createUserAttribute, + createNonePersonalUserAttribute, implementedInApiVersion, - nameOf(createUserAttribute), + nameOf(createNonePersonalUserAttribute), "POST", - "/users/USER_ID/attributes", - "Create User Attribute", - s""" Create User Attribute + "/users/USER_ID/none-personal/attributes", + "Create None Personal User Attribute", + s""" Create None Personal User Attribute | |The type field must be one of "STRING", "INTEGER", "DOUBLE" or DATE_WITH_DAY" | @@ -177,11 +177,11 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canCreateUserAttribute)) + Some(List(canCreateNonePersonalUserAttribute)) ) - lazy val createUserAttribute: OBPEndpoint = { - case "users" :: userId :: "attributes" :: Nil JsonPost json -> _ => { + lazy val createNonePersonalUserAttribute: OBPEndpoint = { + case "users" :: userId ::"none-personal":: "attributes" :: Nil JsonPost json -> _ => { cc => val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV510 " for { @@ -200,7 +200,7 @@ trait APIMethods510 { postedData.name, userAttributeType, postedData.value, - postedData.is_personal, + false, callContext ) } yield { @@ -210,13 +210,13 @@ trait APIMethods510 { } resourceDocs += ResourceDoc( - deleteUserAttribute, + deleteNonePersonalUserAttribute, implementedInApiVersion, - nameOf(deleteUserAttribute), + nameOf(deleteNonePersonalUserAttribute), "DELETE", - "/users/USER_ID/attributes/USER_ATTRIBUTE_ID", - "Delete User Attribute", - s"""Delete the User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID + "/users/USER_ID/none-personal/attributes/USER_ATTRIBUTE_ID", + "Delete None Personal User Attribute", + s"""Delete the None Personal User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID | |${authenticationRequiredMessage(true)} |""".stripMargin, @@ -229,10 +229,10 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canDeleteUserAttribute))) + Some(List(canDeleteNonePersonalUserAttribute))) - lazy val deleteUserAttribute: OBPEndpoint = { - case "users" :: userId :: "attributes" :: userAttributeId :: Nil JsonDelete _ => { + lazy val deleteNonePersonalUserAttribute: OBPEndpoint = { + case "users" :: userId :: "none-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => { cc => for { (_, callContext) <- authenticatedAccess(cc) @@ -250,13 +250,13 @@ trait APIMethods510 { } resourceDocs += ResourceDoc( - getUserAttributes, + getNonePersonalUserAttributes, implementedInApiVersion, - nameOf(getUserAttributes), + nameOf(getNonePersonalUserAttributes), "GET", - "/users/USER_ID/attributes", - "Get User Attributes", - s"""Get User Attribute for a user specified by USER_ID + "/users/USER_ID/none-personal/attributes", + "Get None Personal User Attributes", + s"""Get None Personal User Attribute for a user specified by USER_ID | |${authenticationRequiredMessage(true)} |""".stripMargin, @@ -269,20 +269,18 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canGetUserAttributes))) + Some(List(canGetNonePersonalUserAttributes))) - lazy val getUserAttributes: OBPEndpoint = { - case "users" :: userId :: "attributes" :: Nil JsonGet _ => { + lazy val getNonePersonalUserAttributes: OBPEndpoint = { + case "users" :: userId :: "none-personal" ::"attributes" :: Nil JsonGet _ => { cc => for { (_, callContext) <- authenticatedAccess(cc) (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext) - (userAttributes,callContext) <- Connector.connector.vend.getUserAttributes( + (userAttributes,callContext) <- NewStyle.function.getPersonalUserAttributes( user.userId, callContext, - ) map { - i => (connectorEmptyResponse (i._1, callContext), i._2) - } + ) } yield { (JSONFactory510.createUserAttributesJson(userAttributes), HttpCode.`200`(callContext)) } diff --git a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala index 40a577698..f92161f21 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala @@ -208,8 +208,7 @@ case class UserAttributeResponseJsonV510( case class UserAttributeJsonV510( name: String, `type`: String, - value: String, - is_personal: Boolean + value: String ) case class UserAttributesResponseJsonV510( diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index afb561f12..b32454fda 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -23,9 +23,9 @@ class UserAttributesTest extends V510ServerSetup { * 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.createUserAttribute)) - object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteUserAttribute)) - object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getUserAttributes)) + object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.createNonePersonalUserAttribute)) + object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteNonePersonalUserAttribute)) + object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getNonePersonalUserAttributes)) lazy val bankId = testBankId1.value @@ -37,7 +37,7 @@ class UserAttributesTest extends V510ServerSetup { 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"/ "attributes").POST + val request510 = (v5_1_0_Request / "users" /"testUserId"/ "none-personal" / "attributes").POST val response510 = makePostRequest(request510, write(postUserAttributeJsonV510)) Then("We should get a 401") response510.code should equal(401) @@ -46,7 +46,7 @@ class UserAttributesTest extends V510ServerSetup { 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"/ "attributes"/"testUserAttributeId").DELETE + val request510 = (v5_1_0_Request / "users" /"testUserId" / "none-personal" /"attributes"/"testUserAttributeId").DELETE val response510 = makeDeleteRequest(request510) Then("We should get a 401") response510.code should equal(401) @@ -55,7 +55,7 @@ class UserAttributesTest extends V510ServerSetup { 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"/ "attributes").GET + val request510 = (v5_1_0_Request / "users" /"testUserId" / "none-personal" /"attributes").GET val response510 = makeGetRequest(request510) Then("We should get a 401") response510.code should equal(401) @@ -68,16 +68,16 @@ class UserAttributesTest extends V510ServerSetup { 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.CanCreateUserAttribute.toString) - Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteUserAttribute.toString) - Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetUserAttributes.toString) + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanCreateNonePersonalUserAttribute.toString) + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteNonePersonalUserAttribute.toString) + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetNonePersonalUserAttributes.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 / "attributes").POST <@ (user1) + val request510 = (v5_1_0_Request / "users"/ userId / "none-personal" /"attributes").POST <@ (user1) val response510 = makePostRequest(request510, write(postUserAttributeJsonV510)) Then("We should get a 201") response510.code should equal(201) @@ -87,7 +87,7 @@ class UserAttributesTest extends V510ServerSetup { val userAttributeId = jsonResponse.user_attribute_id { - val request510 = (v5_1_0_Request / "users" / userId / "attributes").GET <@ (user1) + val request510 = (v5_1_0_Request / "users" / userId / "none-personal" /"attributes").GET <@ (user1) val response510 = makeGetRequest(request510) Then("We should get a 200") response510.code should equal(200) @@ -96,7 +96,7 @@ class UserAttributesTest extends V510ServerSetup { jsonResponse.user_attributes.head.name shouldBe (batteryLevel) jsonResponse.user_attributes.head.user_attribute_id shouldBe (userAttributeId) } - val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"attributes"/userAttributeId).DELETE <@ (user1) + val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"attributes"/"none-personal"/userAttributeId).DELETE <@ (user1) val responseDeleteUserAttribute = makeDeleteRequest(requestDeleteUserAttribute) Then("We should get a 204") responseDeleteUserAttribute.code should equal(204) @@ -109,7 +109,7 @@ class UserAttributesTest extends V510ServerSetup { { - val request510 = (v5_1_0_Request / "users" / userId / "attributes").GET <@ (user1) + val request510 = (v5_1_0_Request / "users" / userId / "none-personal" /"attributes").GET <@ (user1) val response510 = makeGetRequest(request510) Then("We should get a 200") response510.code should equal(200) @@ -128,12 +128,12 @@ class UserAttributesTest extends V510ServerSetup { 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 / "attributes").POST <@ (user1) + val request510 = (v5_1_0_Request / "users" / userId / "none-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.CanCreateUserAttribute.toString()) shouldBe (true) + response510.body.extract[ErrorMessage].message contains (ApiRole.CanCreateNonePersonalUserAttribute.toString()) shouldBe (true) } scenario(s"We will call the $ApiEndpoint2 with user credentials, but missing roles", ApiEndpoint1, ApiEndpoint2, VersionOfApi) { @@ -145,12 +145,12 @@ class UserAttributesTest extends V510ServerSetup { 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 / "attributes" / "attributeId").DELETE <@ (user1) + val request510 = (v5_1_0_Request / "users" / userId / "none-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.CanDeleteUserAttribute.toString()) shouldBe (true) + response510.body.extract[ErrorMessage].message contains (ApiRole.CanDeleteNonePersonalUserAttribute.toString()) shouldBe (true) } scenario(s"We will call the $ApiEndpoint3 with user credentials, but missing roles", ApiEndpoint1, ApiEndpoint2, VersionOfApi) { @@ -162,12 +162,12 @@ class UserAttributesTest extends V510ServerSetup { 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 / "attributes" ).GET <@ (user1) + val request510 = (v5_1_0_Request / "users" / userId / "none-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.CanGetUserAttributes.toString()) shouldBe (true) + response510.body.extract[ErrorMessage].message contains (ApiRole.CanGetNonePersonalUserAttributes.toString()) shouldBe (true) } } From 27d2f9e3b3fd49338e3c789a01e0b101d7a1b0a5 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 31 May 2023 20:37:53 +0800 Subject: [PATCH 13/15] refactor/rename NonePersonal to NonPersonal --- .../main/scala/code/api/util/ApiRole.scala | 12 +++++----- .../scala/code/api/v5_1_0/APIMethods510.scala | 24 +++++++++---------- .../remotedata/RemotedataUserAttribute.scala | 4 ++-- .../code/users/MappedUserAttribute.scala | 2 +- .../code/users/UserAttributeProvider.scala | 4 ++-- .../code/api/v5_1_0/UserAttributesTest.scala | 18 +++++++------- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 18c3a357a..439ec4c8a 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -404,14 +404,14 @@ object ApiRole { case class CanGetUsersWithAttributes (requiresBankId: Boolean = false) extends ApiRole lazy val canGetUsersWithAttributes = CanGetUsersWithAttributes() - case class CanCreateNonePersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole - lazy val canCreateNonePersonalUserAttribute = CanCreateNonePersonalUserAttribute() + case class CanCreateNonPersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canCreateNonPersonalUserAttribute = CanCreateNonPersonalUserAttribute() - case class CanGetNonePersonalUserAttributes (requiresBankId: Boolean = false) extends ApiRole - lazy val canGetNonePersonalUserAttributes = CanGetNonePersonalUserAttributes() + case class CanGetNonPersonalUserAttributes (requiresBankId: Boolean = false) extends ApiRole + lazy val canGetNonPersonalUserAttributes = CanGetNonPersonalUserAttributes() - case class CanDeleteNonePersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole - lazy val canDeleteNonePersonalUserAttribute = CanDeleteNonePersonalUserAttribute() + case class CanDeleteNonPersonalUserAttribute (requiresBankId: Boolean = false) extends ApiRole + lazy val canDeleteNonPersonalUserAttribute = CanDeleteNonPersonalUserAttribute() case class CanReadUserLockedStatus(requiresBankId: Boolean = false) extends ApiRole lazy val canReadUserLockedStatus = CanReadUserLockedStatus() diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 3fbfd9f42..43c8d764a 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -155,9 +155,9 @@ trait APIMethods510 { } } staticResourceDocs += ResourceDoc( - createNonePersonalUserAttribute, + createNonPersonalUserAttribute, implementedInApiVersion, - nameOf(createNonePersonalUserAttribute), + nameOf(createNonPersonalUserAttribute), "POST", "/users/USER_ID/none-personal/attributes", "Create None Personal User Attribute", @@ -177,10 +177,10 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canCreateNonePersonalUserAttribute)) + Some(List(canCreateNonPersonalUserAttribute)) ) - lazy val createNonePersonalUserAttribute: OBPEndpoint = { + lazy val createNonPersonalUserAttribute: OBPEndpoint = { case "users" :: userId ::"none-personal":: "attributes" :: Nil JsonPost json -> _ => { cc => val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV510 " @@ -210,9 +210,9 @@ trait APIMethods510 { } resourceDocs += ResourceDoc( - deleteNonePersonalUserAttribute, + deleteNonPersonalUserAttribute, implementedInApiVersion, - nameOf(deleteNonePersonalUserAttribute), + nameOf(deleteNonPersonalUserAttribute), "DELETE", "/users/USER_ID/none-personal/attributes/USER_ATTRIBUTE_ID", "Delete None Personal User Attribute", @@ -229,9 +229,9 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canDeleteNonePersonalUserAttribute))) + Some(List(canDeleteNonPersonalUserAttribute))) - lazy val deleteNonePersonalUserAttribute: OBPEndpoint = { + lazy val deleteNonPersonalUserAttribute: OBPEndpoint = { case "users" :: userId :: "none-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => { cc => for { @@ -250,9 +250,9 @@ trait APIMethods510 { } resourceDocs += ResourceDoc( - getNonePersonalUserAttributes, + getNonPersonalUserAttributes, implementedInApiVersion, - nameOf(getNonePersonalUserAttributes), + nameOf(getNonPersonalUserAttributes), "GET", "/users/USER_ID/none-personal/attributes", "Get None Personal User Attributes", @@ -269,9 +269,9 @@ trait APIMethods510 { UnknownError ), List(apiTagUser, apiTagNewStyle), - Some(List(canGetNonePersonalUserAttributes))) + Some(List(canGetNonPersonalUserAttributes))) - lazy val getNonePersonalUserAttributes: OBPEndpoint = { + lazy val getNonPersonalUserAttributes: OBPEndpoint = { case "users" :: userId :: "none-personal" ::"attributes" :: Nil JsonGet _ => { cc => for { diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala index 1641e73ae..dc8d3902b 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataUserAttribute.scala @@ -22,8 +22,8 @@ object RemotedataUserAttribute extends ObpActorInit with UserAttributeProvider { override def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = (actor ? cc.getPersonalUserAttributes(userId)).mapTo[Box[List[UserAttribute]]] - override def getNonePersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = - (actor ? cc.getNonePersonalUserAttributes(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]]] diff --git a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala index 628e6204b..bbb2dbaa9 100644 --- a/obp-api/src/main/scala/code/users/MappedUserAttribute.scala +++ b/obp-api/src/main/scala/code/users/MappedUserAttribute.scala @@ -29,7 +29,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider { ) ) } - override def getNonePersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { + override def getNonPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] = Future { tryo( UserAttribute.findAll( By(UserAttribute.UserId, userId), diff --git a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala index ab95e2e25..09cfcb5f7 100644 --- a/obp-api/src/main/scala/code/users/UserAttributeProvider.scala +++ b/obp-api/src/main/scala/code/users/UserAttributeProvider.scala @@ -39,7 +39,7 @@ trait UserAttributeProvider { def getUserAttributesByUser(userId: String): Future[Box[List[UserAttribute]]] def getPersonalUserAttributes(userId: String): Future[Box[List[UserAttribute]]] - def getNonePersonalUserAttributes(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, @@ -54,7 +54,7 @@ trait UserAttributeProvider { class RemotedataUserAttributeCaseClasses { case class getUserAttributesByUser(userId: String) case class getPersonalUserAttributes(userId: String) - case class getNonePersonalUserAttributes(userId: String) + case class getNonPersonalUserAttributes(userId: String) case class deleteUserAttribute(userAttributeId: String) case class getUserAttributesByUsers(userIds: List[String]) case class createOrUpdateUserAttribute(userId: String, diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index b32454fda..51fc8f4af 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -23,9 +23,9 @@ class UserAttributesTest extends V510ServerSetup { * 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.createNonePersonalUserAttribute)) - object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.deleteNonePersonalUserAttribute)) - object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getNonePersonalUserAttributes)) + 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 @@ -68,9 +68,9 @@ class UserAttributesTest extends V510ServerSetup { 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.CanCreateNonePersonalUserAttribute.toString) - Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteNonePersonalUserAttribute.toString) - Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanGetNonePersonalUserAttributes.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) @@ -133,7 +133,7 @@ class UserAttributesTest extends V510ServerSetup { 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.CanCreateNonePersonalUserAttribute.toString()) 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) { @@ -150,7 +150,7 @@ class UserAttributesTest extends V510ServerSetup { 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.CanDeleteNonePersonalUserAttribute.toString()) 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) { @@ -167,7 +167,7 @@ class UserAttributesTest extends V510ServerSetup { 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.CanGetNonePersonalUserAttributes.toString()) shouldBe (true) + response510.body.extract[ErrorMessage].message contains (ApiRole.CanGetNonPersonalUserAttributes.toString()) shouldBe (true) } } From 8d304c33966913e2feef0fb36bb572f4edb175b5 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 31 May 2023 22:09:25 +0800 Subject: [PATCH 14/15] refactor/rename None Personal to Non Personal --- .../scala/code/api/v5_1_0/APIMethods510.scala | 24 +++++++++---------- .../code/api/v5_1_0/UserAttributesTest.scala | 20 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 43c8d764a..b3a55252e 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -159,9 +159,9 @@ trait APIMethods510 { implementedInApiVersion, nameOf(createNonPersonalUserAttribute), "POST", - "/users/USER_ID/none-personal/attributes", - "Create None Personal User Attribute", - s""" Create None Personal User Attribute + "/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" | @@ -181,7 +181,7 @@ trait APIMethods510 { ) lazy val createNonPersonalUserAttribute: OBPEndpoint = { - case "users" :: userId ::"none-personal":: "attributes" :: Nil JsonPost json -> _ => { + case "users" :: userId ::"non-personal":: "attributes" :: Nil JsonPost json -> _ => { cc => val failMsg = s"$InvalidJsonFormat The Json body should be the $UserAttributeJsonV510 " for { @@ -214,9 +214,9 @@ trait APIMethods510 { implementedInApiVersion, nameOf(deleteNonPersonalUserAttribute), "DELETE", - "/users/USER_ID/none-personal/attributes/USER_ATTRIBUTE_ID", - "Delete None Personal User Attribute", - s"""Delete the None Personal User Attribute specified by ENTITLEMENT_REQUEST_ID for a user specified by USER_ID + "/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, @@ -232,7 +232,7 @@ trait APIMethods510 { Some(List(canDeleteNonPersonalUserAttribute))) lazy val deleteNonPersonalUserAttribute: OBPEndpoint = { - case "users" :: userId :: "none-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => { + case "users" :: userId :: "non-personal" :: "attributes" :: userAttributeId :: Nil JsonDelete _ => { cc => for { (_, callContext) <- authenticatedAccess(cc) @@ -254,9 +254,9 @@ trait APIMethods510 { implementedInApiVersion, nameOf(getNonPersonalUserAttributes), "GET", - "/users/USER_ID/none-personal/attributes", - "Get None Personal User Attributes", - s"""Get None Personal User Attribute for a user specified by USER_ID + "/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, @@ -272,7 +272,7 @@ trait APIMethods510 { Some(List(canGetNonPersonalUserAttributes))) lazy val getNonPersonalUserAttributes: OBPEndpoint = { - case "users" :: userId :: "none-personal" ::"attributes" :: Nil JsonGet _ => { + case "users" :: userId :: "non-personal" ::"attributes" :: Nil JsonGet _ => { cc => for { (_, callContext) <- authenticatedAccess(cc) diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index 51fc8f4af..3614cc37c 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -37,7 +37,7 @@ class UserAttributesTest extends V510ServerSetup { 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"/ "none-personal" / "attributes").POST + 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) @@ -46,7 +46,7 @@ class UserAttributesTest extends V510ServerSetup { 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" / "none-personal" /"attributes"/"testUserAttributeId").DELETE + 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) @@ -55,7 +55,7 @@ class UserAttributesTest extends V510ServerSetup { 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" / "none-personal" /"attributes").GET + 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) @@ -77,7 +77,7 @@ class UserAttributesTest extends V510ServerSetup { 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 / "none-personal" /"attributes").POST <@ (user1) + 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) @@ -87,7 +87,7 @@ class UserAttributesTest extends V510ServerSetup { val userAttributeId = jsonResponse.user_attribute_id { - val request510 = (v5_1_0_Request / "users" / userId / "none-personal" /"attributes").GET <@ (user1) + 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) @@ -96,7 +96,7 @@ class UserAttributesTest extends V510ServerSetup { jsonResponse.user_attributes.head.name shouldBe (batteryLevel) jsonResponse.user_attributes.head.user_attribute_id shouldBe (userAttributeId) } - val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"attributes"/"none-personal"/userAttributeId).DELETE <@ (user1) + val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"attributes"/"non-personal"/userAttributeId).DELETE <@ (user1) val responseDeleteUserAttribute = makeDeleteRequest(requestDeleteUserAttribute) Then("We should get a 204") responseDeleteUserAttribute.code should equal(204) @@ -109,7 +109,7 @@ class UserAttributesTest extends V510ServerSetup { { - val request510 = (v5_1_0_Request / "users" / userId / "none-personal" /"attributes").GET <@ (user1) + 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) @@ -128,7 +128,7 @@ class UserAttributesTest extends V510ServerSetup { 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 / "none-personal" /"attributes").POST <@ (user1) + 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) @@ -145,7 +145,7 @@ class UserAttributesTest extends V510ServerSetup { 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 / "none-personal" /"attributes" / "attributeId").DELETE <@ (user1) + 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) @@ -162,7 +162,7 @@ class UserAttributesTest extends V510ServerSetup { 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 / "none-personal" /"attributes" ).GET <@ (user1) + 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) From d98789e7514d4918837f58d7ea137b63b6685a12 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 31 May 2023 22:24:24 +0800 Subject: [PATCH 15/15] refactor/added the getNonPersonalUserAttributes method --- obp-api/src/main/scala/code/api/util/NewStyle.scala | 9 +++++++++ .../src/main/scala/code/api/v5_1_0/APIMethods510.scala | 2 +- .../src/main/scala/code/bankconnectors/Connector.scala | 3 +++ .../scala/code/bankconnectors/LocalMappedConnector.scala | 3 +++ .../test/scala/code/api/v5_1_0/UserAttributesTest.scala | 2 +- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 09f66ba0c..f41002514 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1904,6 +1904,15 @@ object NewStyle extends MdcLoggable{ } } + + 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] diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index b3a55252e..721f255df 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -277,7 +277,7 @@ trait APIMethods510 { for { (_, callContext) <- authenticatedAccess(cc) (user, callContext) <- NewStyle.function.getUserByUserId(userId, callContext) - (userAttributes,callContext) <- NewStyle.function.getPersonalUserAttributes( + (userAttributes,callContext) <- NewStyle.function.getNonPersonalUserAttributes( user.userId, callContext, ) diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index e9c63239f..d38abc3d0 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -2262,6 +2262,9 @@ trait Connector extends MdcLoggable { 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]]] = diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 6b203ff7e..9e9131fd5 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -4084,6 +4084,9 @@ object LocalMappedConnector extends Connector with MdcLoggable { 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)} } diff --git a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala index 3614cc37c..b7c117582 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/UserAttributesTest.scala @@ -96,7 +96,7 @@ class UserAttributesTest extends V510ServerSetup { jsonResponse.user_attributes.head.name shouldBe (batteryLevel) jsonResponse.user_attributes.head.user_attribute_id shouldBe (userAttributeId) } - val requestDeleteUserAttribute = (v5_1_0_Request / "users"/ userId/"attributes"/"non-personal"/userAttributeId).DELETE <@ (user1) + 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)