From 98b8ba15d7754523dc67e7ea1772c1f9105501d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20St=C3=B6ckli?= Date: Tue, 17 Dec 2019 15:18:05 +0100 Subject: [PATCH 1/9] test(webapi): add unique username/email check to change user --- .../admin/UsersResponderADMSpec.scala | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala index bb3b3e554a..5ae838fb7d 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala @@ -333,6 +333,30 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with response3.user.familyName should equal (SharedTestDataADM.normalUser.familyName) } + + "return a 'DuplicateValueException' if the supplied 'username' is not unique" in { + responderManager ! UserChangeBasicUserInformationRequestADM( + userIri = SharedTestDataADM.normalUser.id, + changeUserRequest = ChangeUserApiRequestADM( + username = Some("root") + ), + SharedTestDataADM.superUser, + UUID.randomUUID + ) + expectMsg(Failure(DuplicateValueException(s"User with the username: 'root' already exists"))) + } + + "return a 'DuplicateValueException' if the supplied 'email' is not unique" in { + responderManager ! UserChangeBasicUserInformationRequestADM( + userIri = SharedTestDataADM.normalUser.id, + changeUserRequest = ChangeUserApiRequestADM( + email = Some("root@example.com") + ), + SharedTestDataADM.superUser, + UUID.randomUUID + ) + expectMsg(Failure(DuplicateValueException(s"User with the email: 'root@example.com' already exists"))) + } "UPDATE the user's password (by himself)" in { responderManager ! UserChangePasswordRequestADM( From 0b4cdeed44342276aa1ca4c94bbee3880eedb897 Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 23 Dec 2019 16:30:22 +0100 Subject: [PATCH 2/9] fix(webapi): fix unique username and email check --- .../responders/admin/UsersResponderADM.scala | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index 27b11817d9..b18acd8e2d 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -39,7 +39,7 @@ import org.knora.webapi.util.IriConversions._ import org.knora.webapi.util.{InstrumentationSupport, SmartIri} import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import scala.concurrent.Future +import scala.concurrent.{Await, Future} /** * Provides information about Knora users to other responders. @@ -261,28 +261,19 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // check if we want to change the email _ = if (changeUserRequest.email.isDefined) { - currentUserInformation.map { user => - // check if current email differs from the one in the change request - if (!user.email.equals(changeUserRequest.email.get)) { - // check if new email is free - userByEmailExists(changeUserRequest.email.get).map(result => - if (result) throw DuplicateValueException("A user with this email exists already. Cannot change") - ) - } + val email = currentUserInformation.get.email + if (!email.equals(changeUserRequest.email.get)) { + val result = userByEmailExists(changeUserRequest.email.get) + if (Await.result(result, timeout.duration)) throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") } } // check if we want to change the username _ = if (changeUserRequest.username.isDefined) { - currentUserInformation.map { user => - // check if the current username differs from the one in the change request - if (!user.username.equals(changeUserRequest.username.get)) { - // check if new username is free - userByUsernameExists(changeUserRequest.email.get).map(result => - if (result) throw DuplicateValueException("A user with this username exists already. Cannot change") - ) - } - + val user = currentUserInformation.get.username + if (!user.equals(changeUserRequest.username.get)) { + val result = userByUsernameExists(changeUserRequest.username.get) + if (Await.result(result, timeout.duration)) throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") } } From 1c8899ed8e200c10665c4587b8bfb8c8851df7cb Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 7 Jan 2020 14:55:09 +0100 Subject: [PATCH 3/9] fix(webapi): remove mean blocking awaits --- .../responders/admin/UsersResponderADM.scala | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index b18acd8e2d..430eed818c 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -260,21 +260,15 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde ) // check if we want to change the email - _ = if (changeUserRequest.email.isDefined) { - val email = currentUserInformation.get.email - if (!email.equals(changeUserRequest.email.get)) { - val result = userByEmailExists(changeUserRequest.email.get) - if (Await.result(result, timeout.duration)) throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") - } + emailTaken: Boolean <- userByEmailExists(changeUserRequest.email.getOrElse("")) + _ = if (emailTaken && changeUserRequest.email.isDefined) { + throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") } // check if we want to change the username - _ = if (changeUserRequest.username.isDefined) { - val user = currentUserInformation.get.username - if (!user.equals(changeUserRequest.username.get)) { - val result = userByUsernameExists(changeUserRequest.username.get) - if (Await.result(result, timeout.duration)) throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") - } + usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username.getOrElse("")) + _ = if (usernameTaken && changeUserRequest.username.isDefined) { + throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") } userUpdatePayload = UserUpdatePayloadADM( @@ -1401,14 +1395,19 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * @return a [[Boolean]]. */ private def userByUsernameExists(username: String): Future[Boolean] = { - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username).toString) - // _ = log.debug("userExists - query: {}", askString) + username match { + case "" => FastFuture.successful(false) + case _ => { + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username).toString) + // _ = log.debug("userExists - query: {}", askString) - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + result = checkUserExistsResponse.result - } yield result + } yield result + } + } } /** @@ -1418,14 +1417,19 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * @return a [[Boolean]]. */ private def userByEmailExists(email: String): Future[Boolean] = { - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString) - // _ = log.debug("userExists - query: {}", askString) + email match { + case "" => FastFuture.successful(false) + case _ => { + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString) + // _ = log.debug("userExists - query: {}", askString) - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + result = checkUserExistsResponse.result - } yield result + } yield result + } + } } /** From 4571343b935dd94d0884796cbdf4a3274c2621de Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 7 Jan 2020 15:11:08 +0100 Subject: [PATCH 4/9] fix(webapi): remove unnecessary comparison in change user --- .../org/knora/webapi/responders/admin/UsersResponderADM.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index 430eed818c..cb4be462c4 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -261,13 +261,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // check if we want to change the email emailTaken: Boolean <- userByEmailExists(changeUserRequest.email.getOrElse("")) - _ = if (emailTaken && changeUserRequest.email.isDefined) { + _ = if (emailTaken) { throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") } // check if we want to change the username usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username.getOrElse("")) - _ = if (usernameTaken && changeUserRequest.username.isDefined) { + _ = if (usernameTaken) { throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") } From 2901f7f67546cc7e3e9bcdbc8ca0b0cc32ce70d8 Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 7 Jan 2020 16:06:09 +0100 Subject: [PATCH 5/9] refactor(webapi): remove unused import --- .../org/knora/webapi/responders/admin/UsersResponderADM.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index cb4be462c4..ea67db2626 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -39,7 +39,7 @@ import org.knora.webapi.util.IriConversions._ import org.knora.webapi.util.{InstrumentationSupport, SmartIri} import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import scala.concurrent.{Await, Future} +import scala.concurrent.Future /** * Provides information about Knora users to other responders. From 09851597756085264bf2bbd32c089c35ef68196e Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 27 Apr 2020 15:06:01 +0200 Subject: [PATCH 6/9] fix(webapi):check if requested email and username equal current values --- .../webapi/responders/admin/UsersResponderADM.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index ea67db2626..66a3751808 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -260,13 +260,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde ) // check if we want to change the email - emailTaken: Boolean <- userByEmailExists(changeUserRequest.email.getOrElse("")) + emailTaken: Boolean <- userByEmailExists(changeUserRequest.email.getOrElse(""), currentUserInformation.get.email) _ = if (emailTaken) { throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") } // check if we want to change the username - usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username.getOrElse("")) + usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username.getOrElse(""), currentUserInformation.get.username) _ = if (usernameTaken) { throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") } @@ -1392,11 +1392,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Helper method for checking if an username is already registered. * * @param username the username of the user. + * @param current the current username of the user. * @return a [[Boolean]]. */ - private def userByUsernameExists(username: String): Future[Boolean] = { + private def userByUsernameExists(username: String, current: String = ""): Future[Boolean] = { username match { case "" => FastFuture.successful(false) + case `current` => FastFuture.successful(true) case _ => { for { askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username).toString) @@ -1414,11 +1416,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Helper method for checking if an email is already registered. * * @param email the email of the user. + * @param current the current email of the user. * @return a [[Boolean]]. */ - private def userByEmailExists(email: String): Future[Boolean] = { + private def userByEmailExists(email: String, current: String = ""): Future[Boolean] = { email match { case "" => FastFuture.successful(false) + case `current` => FastFuture.successful(true) case _ => { for { askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString) From 44e068cc27dd89ce6b5b2e03202807ad9310e645 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 29 Apr 2020 22:09:58 +0200 Subject: [PATCH 7/9] fix(webapi): replace '""' with 'None' for values that don't exist --- .../responders/admin/UsersResponderADM.scala | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index f42492465c..b63d1ac646 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -265,13 +265,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } // check if we want to change the email - emailTaken: Boolean <- userByEmailExists(changeUserRequest.email.getOrElse(""), currentUserInformation.get.email) + emailTaken: Boolean <- userByEmailExists(changeUserRequest.email, Some(currentUserInformation.get.email)) _ = if (emailTaken) { throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") } // check if we want to change the username - usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username.getOrElse(""), currentUserInformation.get.username) + usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username, Some(currentUserInformation.get.username)) _ = if (usernameTaken) { throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") } @@ -1170,12 +1170,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde _ = if (createRequest.givenName.isEmpty) throw BadRequestException("Given name cannot be empty") _ = if (createRequest.familyName.isEmpty) throw BadRequestException("Family name cannot be empty") - usernameTaken: Boolean <- userByUsernameExists(createRequest.username) + usernameTaken: Boolean <- userByUsernameExists(Some(createRequest.username)) _ = if (usernameTaken) { throw DuplicateValueException(s"User with the username: '${createRequest.username}' already exists") } - emailTaken: Boolean <- userByEmailExists(createRequest.email) + emailTaken: Boolean <- userByEmailExists(Some(createRequest.email)) _ = if (emailTaken) { throw DuplicateValueException(s"User with the email: '${createRequest.email}' already exists") } @@ -1406,21 +1406,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * @param current the current username of the user. * @return a [[Boolean]]. */ - private def userByUsernameExists(username: String, current: String = ""): Future[Boolean] = { - username match { - case "" => FastFuture.successful(false) - case `current` => FastFuture.successful(true) - case _ => { - stringFormatter.validateUsername(username, throw BadRequestException(s"The username: '${username}' contains invalid characters")) - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username).toString) - // _ = log.debug("userExists - query: {}", askString) - - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result - - } yield result - } + private def userByUsernameExists(username: Option[String], current: Option[String] = None): Future[Boolean] = { + if (!username.isDefined) { + FastFuture.successful(false) + } else if (current.isDefined && username.get.equals(current.get)) { + FastFuture.successful(true) + } else { + stringFormatter.validateUsername(username.get, throw BadRequestException(s"The username: '${username.get}' contains invalid characters")) + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username.get).toString) + // _ = log.debug("userExists - query: {}", askString) + + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + result = checkUserExistsResponse.result + + } yield result } } @@ -1431,21 +1431,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * @param current the current email of the user. * @return a [[Boolean]]. */ - private def userByEmailExists(email: String, current: String = ""): Future[Boolean] = { - email match { - case "" => FastFuture.successful(false) - case `current` => FastFuture.successful(true) - case _ => { - stringFormatter.validateEmailAndThrow(email, throw BadRequestException(s"The email: '${email}' is invalid")) - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString) - // _ = log.debug("userExists - query: {}", askString) - - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result - - } yield result - } + private def userByEmailExists(email: Option[String], current: Option[String] = None): Future[Boolean] = { + if (!email.isDefined) { + FastFuture.successful(false) + } else if (current.isDefined && email.get.equals(current.get)) { + FastFuture.successful(true) + } else { + stringFormatter.validateEmailAndThrow(email.get, throw BadRequestException(s"The email: '${email.get}' is invalid")) + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email.get).toString) + // _ = log.debug("userExists - query: {}", askString) + + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + result = checkUserExistsResponse.result + + } yield result } } From ec1f67ce03bca98123842e3ec7e9a65d05591ab0 Mon Sep 17 00:00:00 2001 From: Benjamin Geer Date: Thu, 4 Jun 2020 14:36:18 +0200 Subject: [PATCH 8/9] refactor(UsersResponderADM): Avoid using Option.get. --- .../responders/admin/UsersResponderADM.scala | 613 +++++++++--------- 1 file changed, 307 insertions(+), 306 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index b63d1ac646..ce2b58561b 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -42,16 +42,16 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import scala.concurrent.Future /** - * Provides information about Knora users to other responders. - */ + * Provides information about Knora users to other responders. + */ class UsersResponderADM(responderData: ResponderData) extends Responder(responderData) with InstrumentationSupport { // The IRI used to lock user creation and update private val USERS_GLOBAL_LOCK_IRI = "http://rdfh.ch/users" /** - * Receives a message extending [[UsersResponderRequestV1]], and returns an appropriate message. - */ + * Receives a message extending [[UsersResponderRequestV1]], and returns an appropriate message. + */ def receive(msg: UsersResponderRequestADM) = msg match { case UsersGetADM(userInformationTypeADM, requestingUser) => getAllUserADM(userInformationTypeADM, requestingUser) case UsersGetRequestADM(userInformationTypeADM, requestingUser) => getAllUserADMRequest(userInformationTypeADM, requestingUser) @@ -76,12 +76,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Gets all the users and returns them as a sequence of [[UserADM]]. - * - * @param userInformationType the extent of the information returned. - * @param requestingUser the user initiating the request. - * @return all the users as a sequence of [[UserADM]]. - */ + * Gets all the users and returns them as a sequence of [[UserADM]]. + * + * @param userInformationType the extent of the information returned. + * @param requestingUser the user initiating the request. + * @return all the users as a sequence of [[UserADM]]. + */ private def getAllUserADM(userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[Seq[UserADM]] = { //log.debug("getAllUserADM") @@ -123,12 +123,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Gets all the users and returns them as a [[UsersGetResponseADM]]. - * - * @param userInformationType the extent of the information returned. - * @param requestingUser the user initiating the request. - * @return all the users as a [[UsersGetResponseV1]]. - */ + * Gets all the users and returns them as a [[UsersGetResponseADM]]. + * + * @param userInformationType the extent of the information returned. + * @param requestingUser the user initiating the request. + * @return all the users as a [[UsersGetResponseV1]]. + */ private def getAllUserADMRequest(userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[UsersGetResponseADM] = { for { maybeUsersListToReturn <- getAllUserADM(userInformationType, requestingUser) @@ -142,20 +142,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * ~ CACHED ~ - * Gets information about a Knora user, and returns it as a [[UserADM]]. - * If possible, tries to retrieve it from the cache. If not, it retrieves - * it from the triplestore, and then writes it to the cache. Writes to the - * cache are always `UserInformationTypeADM.FULL`. - * - * @param identifier the IRI, email, or username of the user. - * @param userInformationType the type of the requested profile (restricted - * of full). - * @param requestingUser the user initiating the request. - * @param skipCache the flag denotes to skip the cache and instead - * get data from the triplestore - * @return a [[UserADM]] describing the user. - */ + * ~ CACHED ~ + * Gets information about a Knora user, and returns it as a [[UserADM]]. + * If possible, tries to retrieve it from the cache. If not, it retrieves + * it from the triplestore, and then writes it to the cache. Writes to the + * cache are always `UserInformationTypeADM.FULL`. + * + * @param identifier the IRI, email, or username of the user. + * @param userInformationType the type of the requested profile (restricted + * of full). + * @param requestingUser the user initiating the request. + * @param skipCache the flag denotes to skip the cache and instead + * get data from the triplestore + * @return a [[UserADM]] describing the user. + */ private def getSingleUserADM(identifier: UserIdentifierADM, userInformationType: UserInformationTypeADM, requestingUser: UserADM, @@ -196,13 +196,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Gets information about a Knora user, and returns it as a [[UserResponseADM]]. - * - * @param identifier the IRI, username, or email of the user. - * @param userInformationType the type of the requested profile (restricted of full). - * @param requestingUser the user initiating the request. - * @return a [[UserResponseADM]] - */ + * Gets information about a Knora user, and returns it as a [[UserResponseADM]]. + * + * @param identifier the IRI, username, or email of the user. + * @param userInformationType the type of the requested profile (restricted of full). + * @param requestingUser the user initiating the request. + * @return a [[UserResponseADM]] + */ private def getSingleUserADMRequest(identifier: UserIdentifierADM, userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[UserResponseADM] = { for { maybeUserADM <- getSingleUserADM(identifier, userInformationType, requestingUser) @@ -214,26 +214,25 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } - /** - * Updates an existing user. Only basic user data information (username, email, givenName, familyName, lang) - * can be changed. For changing the password or user status, use the separate methods. - * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the updated information. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a future containing a [[UserOperationResponseADM]]. - * @throws BadRequestException if the necessary parameters are not supplied. - * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. - */ + * Updates an existing user. Only basic user data information (username, email, givenName, familyName, lang) + * can be changed. For changing the password or user status, use the separate methods. + * + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the updated information. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a future containing a [[UserOperationResponseADM]]. + * @throws BadRequestException if the necessary parameters are not supplied. + * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. + */ private def changeBasicUserInformationADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { //log.debug(s"changeBasicUserDataV1: changeUserRequest: {}", changeUserRequest) /** - * The actual change basic user data task run with an IRI lock. - */ + * The actual change basic user data task run with an IRI lock. + */ def changeBasicUserDataTask(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if the requesting user is allowed to perform updates @@ -252,8 +251,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde _ = if (parametersCount == 0) throw BadRequestException("At least one parameter needs to be supplied. No data would be changed. Aborting request for changing of basic user data.") // get current user information - currentUserInformation: Option[UserADM] - <- getSingleUserADM( + currentUserInformation: Option[UserADM] <- getSingleUserADM( UserIdentifierADM(maybeIri = Some(userIri)), UserInformationTypeADM.FULL, KnoraSystemInstances.Users.SystemUser @@ -300,18 +298,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Change the users password. The old password needs to be supplied for security purposes. - * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the current password of the requesting user and the new password. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a future containing a [[UserOperationResponseADM]]. - * @throws BadRequestException if necessary parameters are not supplied. - * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. - * @throws ForbiddenException if the supplied old password doesn't match with the user's current password. - * @throws NotFoundException if the user is not found. - */ + * Change the users password. The old password needs to be supplied for security purposes. + * + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the current password of the requesting user and the new password. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a future containing a [[UserOperationResponseADM]]. + * @throws BadRequestException if necessary parameters are not supplied. + * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. + * @throws ForbiddenException if the supplied old password doesn't match with the user's current password. + * @throws NotFoundException if the user is not found. + */ private def changePasswordADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"changePasswordADM - userIri: {}", userIri) @@ -319,8 +317,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde log.debug(s"changePasswordADM - requestingUser: {}", requestingUser) /** - * The actual change password task run with an IRI lock. - */ + * The actual change password task run with an IRI lock. + */ def changePasswordTask(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -360,23 +358,23 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Change the user's status (active / inactive). - * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the new status. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a future containing a [[UserOperationResponseADM]]. - * @throws BadRequestException if necessary parameters are not supplied. - * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. - */ + * Change the user's status (active / inactive). + * + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the new status. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a future containing a [[UserOperationResponseADM]]. + * @throws BadRequestException if necessary parameters are not supplied. + * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. + */ private def changeUserStatusADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"changeUserStatusADM - changeUserRequest: {}", changeUserRequest) /** - * The actual change user status task run with an IRI lock. - */ + * The actual change user status task run with an IRI lock. + */ def changeUserStatusTask(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { _ <- Future( @@ -410,23 +408,23 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Change the user's system admin membership status (active / inactive). - * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the new status. - * @param requestingUser the user profile of the requesting user. - * @param apiRequestID the unique api request ID. - * @return a future containing a [[UserOperationResponseADM]]. - * @throws BadRequestException if necessary parameters are not supplied. - * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. - */ + * Change the user's system admin membership status (active / inactive). + * + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the new status. + * @param requestingUser the user profile of the requesting user. + * @param apiRequestID the unique api request ID. + * @return a future containing a [[UserOperationResponseADM]]. + * @throws BadRequestException if necessary parameters are not supplied. + * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. + */ private def changeUserSystemAdminMembershipStatusADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { //log.debug(s"changeUserSystemAdminMembershipStatusV1: changeUserRequest: {}", changeUserRequest) /** - * The actual change user status task run with an IRI lock. - */ + * The actual change user status task run with an IRI lock. + */ def changeUserSystemAdminMembershipStatusTask(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -460,13 +458,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Returns user's project memberships as a sequence of [[ProjectADM]]. - * - * @param userIri the IRI of the user. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a sequence of [[ProjectADM]] - */ + * Returns user's project memberships as a sequence of [[ProjectADM]]. + * + * @param userIri the IRI of the user. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a sequence of [[ProjectADM]] + */ private def userProjectMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[ProjectADM]] = { for { maybeUser <- getSingleUserADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), userInformationType = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) @@ -480,13 +478,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Returns the user's project memberships as [[UserProjectMembershipsGetResponseADM]]. - * - * @param userIri the user's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a [[UserProjectMembershipsGetResponseADM]]. - */ + * Returns the user's project memberships as [[UserProjectMembershipsGetResponseADM]]. + * + * @param userIri the user's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a [[UserProjectMembershipsGetResponseADM]]. + */ private def userProjectMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserProjectMembershipsGetResponseADM] = { for { @@ -501,21 +499,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Adds a user to a project. - * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return - */ + * Adds a user to a project. + * + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return + */ private def userProjectMembershipAddRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"userProjectMembershipAddRequestADM: userIri: {}, projectIri: {}", userIri, projectIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userProjectMembershipAddRequestTask(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -573,21 +571,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Removes a user from a project. - * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return - */ + * Removes a user from a project. + * + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return + */ private def userProjectMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userProjectMembershipRemoveRequestTask(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -643,13 +641,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Returns the user's project admin group memberships as a sequence of [[IRI]] - * - * @param userIri the user's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a [[UserProjectMembershipsGetResponseV1]]. - */ + * Returns the user's project admin group memberships as a sequence of [[IRI]] + * + * @param userIri the user's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a [[UserProjectMembershipsGetResponseV1]]. + */ private def userProjectAdminMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[ProjectADM]] = { // ToDo: only allow system user @@ -686,14 +684,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Returns the user's project admin group memberships, where the result contains the IRIs of the projects the user - * is a member of the project admin group. - * - * @param userIri the user's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a [[UserProjectMembershipsGetResponseV1]]. - */ + * Returns the user's project admin group memberships, where the result contains the IRIs of the projects the user + * is a member of the project admin group. + * + * @param userIri the user's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a [[UserProjectMembershipsGetResponseV1]]. + */ private def userProjectAdminMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserProjectAdminMembershipsGetResponseADM] = { // ToDo: which user is allowed to do this operation? @@ -710,21 +708,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Adds a user to the project admin group of a project. - * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return - */ + * Adds a user to the project admin group of a project. + * + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return + */ private def userProjectAdminMembershipAddRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectAdminMembershipAddRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userProjectAdminMembershipAddRequestTask(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -782,21 +780,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Removes a user from project admin group of a project. - * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return - */ + * Removes a user from project admin group of a project. + * + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return + */ private def userProjectAdminMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectAdminMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userProjectAdminMembershipRemoveRequestTask(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -853,13 +851,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Returns the user's group memberships as a sequence of [[GroupADM]] - * - * @param userIri the IRI of the user. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a sequence of [[GroupADM]]. - */ + * Returns the user's group memberships as a sequence of [[GroupADM]] + * + * @param userIri the IRI of the user. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a sequence of [[GroupADM]]. + */ private def userGroupMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[GroupADM]] = { for { @@ -877,13 +875,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Returns the user's group memberships as a [[UserGroupMembershipsGetResponseADM]] - * - * @param userIri the IRI of the user. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a [[UserGroupMembershipsGetResponseADM]]. - */ + * Returns the user's group memberships as a [[UserGroupMembershipsGetResponseADM]] + * + * @param userIri the IRI of the user. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a [[UserGroupMembershipsGetResponseADM]]. + */ private def userGroupMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserGroupMembershipsGetResponseADM] = { for { @@ -894,21 +892,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Adds a user to a group. - * - * @param userIri the user's IRI. - * @param groupIri the group IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a [[UserOperationResponseADM]]. - */ + * Adds a user to a group. + * + * @param userIri the user's IRI. + * @param groupIri the group IRI. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a [[UserOperationResponseADM]]. + */ private def userGroupMembershipAddRequestADM(userIri: IRI, groupIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"userGroupMembershipAddRequestADM - userIri: {}, groupIri: {}", userIri, groupIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userGroupMembershipAddRequestTask(userIri: IRI, groupIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -977,8 +975,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde log.debug(s"userGroupMembershipRemoveRequestADM - userIri: {}, groupIri: {}", userIri, groupIri) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def userGroupMembershipRemoveRequestTask(userIri: IRI, groupIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = for { // check if necessary information is present @@ -1044,16 +1042,16 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Updates an existing user. Should not be directly used from the receive method. - * - * @param userIri the IRI of the existing user that we want to update. - * @param userUpdatePayload the updated information. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. - * @return a future containing a [[UserOperationResponseADM]]. - * @throws BadRequestException if necessary parameters are not supplied. - * @throws UpdateNotPerformedException if the update was not performed. - */ + * Updates an existing user. Should not be directly used from the receive method. + * + * @param userIri the IRI of the existing user that we want to update. + * @param userUpdatePayload the updated information. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. + * @return a future containing a [[UserOperationResponseADM]]. + * @throws BadRequestException if necessary parameters are not supplied. + * @throws UpdateNotPerformedException if the update was not performed. + */ private def updateUserADM(userIri: IRI, userUpdatePayload: UserUpdatePayloadADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug("updateUserADM - userUpdatePayload: {}", userUpdatePayload) @@ -1138,24 +1136,24 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Creates a new user. Self-registration is allowed, so even the default user, i.e. with no credentials supplied, - * is allowed to create a new user. - * - * Referenced Websites: - * - https://crackstation.net/hashing-security.htm - * - http://blog.ircmaxell.com/2012/12/seven-ways-to-screw-up-bcrypt.html - * - * @param createRequest a [[CreateUserApiRequestADM]] object containing information about the new user to be created. - * @param requestingUser a [[UserADM]] object containing information about the requesting user. - * @return a future containing the [[UserOperationResponseADM]]. - */ + * Creates a new user. Self-registration is allowed, so even the default user, i.e. with no credentials supplied, + * is allowed to create a new user. + * + * Referenced Websites: + * - https://crackstation.net/hashing-security.htm + * - http://blog.ircmaxell.com/2012/12/seven-ways-to-screw-up-bcrypt.html + * + * @param createRequest a [[CreateUserApiRequestADM]] object containing information about the new user to be created. + * @param requestingUser a [[UserADM]] object containing information about the requesting user. + * @return a future containing the [[UserOperationResponseADM]]. + */ private def createNewUserADM(createRequest: CreateUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug("createNewUserADM - createRequest: {}", createRequest) /** - * The actual task run with an IRI lock. - */ + * The actual task run with an IRI lock. + */ def createNewUserTask(createRequest: CreateUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID) = for { // check username _ <- Future(if (createRequest.username.isEmpty) throw BadRequestException("Username cannot be empty")) @@ -1204,8 +1202,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde createNewUserResponse <- (storeManager ? SparqlUpdateRequest(createNewUserSparqlString)).mapTo[SparqlUpdateResponse] // try to retrieve newly created user (will also add to cache) - maybeNewUserADM: Option[UserADM] - <- getSingleUserADM( + maybeNewUserADM: Option[UserADM] <- getSingleUserADM( identifier = UserIdentifierADM(maybeIri = Some(userIri)), requestingUser = KnoraSystemInstances.Users.SystemUser, userInformationType = UserInformationTypeADM.FULL, @@ -1238,32 +1235,32 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde //////////////////// /** - * Tries to retrieve a [[UserADM]] either from triplestore or cache if caching is enabled. - * If user is not found in cache but in triplestore, then user is written to cache. - */ + * Tries to retrieve a [[UserADM]] either from triplestore or cache if caching is enabled. + * If user is not found in cache but in triplestore, then user is written to cache. + */ private def getUserFromCacheOrTriplestore(identifier: UserIdentifierADM): Future[Option[UserADM]] = { if (settings.cacheServiceEnabled) { // caching enabled getUserFromCache(identifier) - .flatMap { - case None => - // none found in cache. getting from triplestore. - getUserFromTriplestore(identifier) - .flatMap { - case None => - // also none found in triplestore. finally returning none. - log.debug("getUserFromCacheOrTriplestore - not found in cache and in triplestore") - FastFuture.successful(None) - case Some(user) => - // found a user in the triplestore. need to write to cache. - log.debug("getUserFromCacheOrTriplestore - not found in cache but found in triplestore. need to write to cache.") - // writing user to cache and afterwards returning the user found in the triplestore - writeUserADMToCache(user).map(res => Some(user)) - } - case Some(user) => - log.debug("getUserFromCacheOrTriplestore - found in cache. returning user.") - FastFuture.successful(Some(user)) - } + .flatMap { + case None => + // none found in cache. getting from triplestore. + getUserFromTriplestore(identifier) + .flatMap { + case None => + // also none found in triplestore. finally returning none. + log.debug("getUserFromCacheOrTriplestore - not found in cache and in triplestore") + FastFuture.successful(None) + case Some(user) => + // found a user in the triplestore. need to write to cache. + log.debug("getUserFromCacheOrTriplestore - not found in cache but found in triplestore. need to write to cache.") + // writing user to cache and afterwards returning the user found in the triplestore + writeUserADMToCache(user).map(res => Some(user)) + } + case Some(user) => + log.debug("getUserFromCacheOrTriplestore - found in cache. returning user.") + FastFuture.successful(Some(user)) + } } else { // caching disabled log.debug("getUserFromCacheOrTriplestore - caching disabled. getting from triplestore.") @@ -1272,8 +1269,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Tries to retrieve a [[UserADM]] from the triplestore. - */ + * Tries to retrieve a [[UserADM]] from the triplestore. + */ private def getUserFromTriplestore(identifier: UserIdentifierADM): Future[Option[UserADM]] = for { sparqlQueryString <- Future(queries.sparql.admin.txt.getUsers( triplestore = settings.triplestoreType, @@ -1295,11 +1292,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** - * Helper method used to create a [[UserADM]] from the [[SparqlExtendedConstructResponse]] containing user data. - * - * @param statements result from the SPARQL query containing user data. - * @return a [[UserADM]] containing the user's data. - */ + * Helper method used to create a [[UserADM]] from the [[SparqlExtendedConstructResponse]] containing user data. + * + * @param statements result from the SPARQL query containing user data. + * @return a [[UserADM]] containing the user's data. + */ private def statements2UserADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]])): Future[Option[UserADM]] = { // log.debug("statements2UserADM - statements: {}", statements) @@ -1383,11 +1380,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Helper method for checking if a user exists. - * - * @param userIri the IRI of the user. - * @return a [[Boolean]]. - */ + * Helper method for checking if a user exists. + * + * @param userIri the IRI of the user. + * @return a [[Boolean]]. + */ private def userExists(userIri: IRI): Future[Boolean] = { for { askString <- Future(queries.sparql.admin.txt.checkUserExists(userIri = userIri).toString) @@ -1400,61 +1397,65 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Helper method for checking if an username is already registered. - * - * @param username the username of the user. - * @param current the current username of the user. - * @return a [[Boolean]]. - */ - private def userByUsernameExists(username: Option[String], current: Option[String] = None): Future[Boolean] = { - if (!username.isDefined) { - FastFuture.successful(false) - } else if (current.isDefined && username.get.equals(current.get)) { - FastFuture.successful(true) - } else { - stringFormatter.validateUsername(username.get, throw BadRequestException(s"The username: '${username.get}' contains invalid characters")) - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username.get).toString) - // _ = log.debug("userExists - query: {}", askString) - - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result + * Helper method for checking if an username is already registered. + * + * @param maybeUsername the username of the user. + * @param maybeCurrent the current username of the user. + * @return a [[Boolean]]. + */ + private def userByUsernameExists(maybeUsername: Option[String], maybeCurrent: Option[String] = None): Future[Boolean] = { + maybeUsername match { + case Some(username) => + if (maybeCurrent.contains(username)) { + FastFuture.successful(true) + } else { + stringFormatter.validateUsername(username, throw BadRequestException(s"The username '$username' contains invalid characters")) + + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByUsername(username = username).toString) + // _ = log.debug("userExists - query: {}", askString) + + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + } yield checkUserExistsResponse.result + } - } yield result + case None => FastFuture.successful(false) } } /** - * Helper method for checking if an email is already registered. - * - * @param email the email of the user. - * @param current the current email of the user. - * @return a [[Boolean]]. - */ - private def userByEmailExists(email: Option[String], current: Option[String] = None): Future[Boolean] = { - if (!email.isDefined) { - FastFuture.successful(false) - } else if (current.isDefined && email.get.equals(current.get)) { - FastFuture.successful(true) - } else { - stringFormatter.validateEmailAndThrow(email.get, throw BadRequestException(s"The email: '${email.get}' is invalid")) - for { - askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email.get).toString) - // _ = log.debug("userExists - query: {}", askString) - - checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] - result = checkUserExistsResponse.result + * Helper method for checking if an email is already registered. + * + * @param maybeEmail the email of the user. + * @param maybeCurrent the current email of the user. + * @return a [[Boolean]]. + */ + private def userByEmailExists(maybeEmail: Option[String], maybeCurrent: Option[String] = None): Future[Boolean] = { + maybeEmail match { + case Some(email) => + if (maybeCurrent.contains(email)) { + FastFuture.successful(true) + } else { + stringFormatter.validateEmailAndThrow(email, throw BadRequestException(s"The email address '$email' is invalid")) + + for { + askString <- Future(queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString) + // _ = log.debug("userExists - query: {}", askString) + + checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse] + } yield checkUserExistsResponse.result + } - } yield result + case None => FastFuture.successful(false) } } /** - * Helper method for checking if a project exists. - * - * @param projectIri the IRI of the project. - * @return a [[Boolean]]. - */ + * Helper method for checking if a project exists. + * + * @param projectIri the IRI of the project. + * @return a [[Boolean]]. + */ private def projectExists(projectIri: IRI): Future[Boolean] = { for { askString <- Future(queries.sparql.admin.txt.checkProjectExistsByIri(projectIri = projectIri).toString) @@ -1467,11 +1468,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Helper method for checking if a group exists. - * - * @param groupIri the IRI of the group. - * @return a [[Boolean]]. - */ + * Helper method for checking if a group exists. + * + * @param groupIri the IRI of the group. + * @return a [[Boolean]]. + */ private def groupExists(groupIri: IRI): Future[Boolean] = { for { askString <- Future(queries.sparql.admin.txt.checkGroupExistsByIri(groupIri = groupIri).toString) @@ -1484,8 +1485,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Tries to retrieve a [[UserADM]] from the cache. - */ + * Tries to retrieve a [[UserADM]] from the cache. + */ private def getUserFromCache(identifier: UserIdentifierADM): Future[Option[UserADM]] = { val result = (storeManager ? CacheServiceGetUserADM(identifier)).mapTo[Option[UserADM]] result.map { @@ -1499,12 +1500,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Writes the user profile to cache. - * - * @param user a [[UserADM]]. - * @return true if writing was successful. - * @throws ApplicationCacheException when there is a problem with writing the user's profile to cache. - */ + * Writes the user profile to cache. + * + * @param user a [[UserADM]]. + * @return true if writing was successful. + * @throws ApplicationCacheException when there is a problem with writing the user's profile to cache. + */ private def writeUserADMToCache(user: UserADM): Future[Boolean] = { val result = (storeManager ? CacheServicePutUserADM(user)).mapTo[Boolean] result.map { res => @@ -1514,10 +1515,10 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } /** - * Removes the user from cache. - */ + * Removes the user from cache. + */ private def invalidateCachedUserADM(maybeUser: Option[UserADM]): Future[Boolean] = { - if(settings.cacheServiceEnabled) { + if (settings.cacheServiceEnabled) { val keys: Set[String] = Seq(maybeUser.map(_.id), maybeUser.map(_.email), maybeUser.map(_.username)).flatten.toSet // only send to Redis if keys are not empty if (keys.nonEmpty) { From 3ce6c3f9493ec1e6981bd07b810a8245fd93b21a Mon Sep 17 00:00:00 2001 From: Benjamin Geer Date: Wed, 24 Jun 2020 16:59:55 +0200 Subject: [PATCH 9/9] test: Fix tests by making error messages consistent. --- .../responders/admin/UsersResponderADM.scala | 14 ++++++------- .../admin/UsersResponderADMSpec.scala | 20 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index ce2b58561b..18d57c9208 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -265,13 +265,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // check if we want to change the email emailTaken: Boolean <- userByEmailExists(changeUserRequest.email, Some(currentUserInformation.get.email)) _ = if (emailTaken) { - throw DuplicateValueException(s"User with the email: '${changeUserRequest.email.get}' already exists") + throw DuplicateValueException(s"User with the email '${changeUserRequest.email.get}' already exists") } // check if we want to change the username usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username, Some(currentUserInformation.get.username)) _ = if (usernameTaken) { - throw DuplicateValueException(s"User with the username: '${changeUserRequest.username.get}' already exists") + throw DuplicateValueException(s"User with the username '${changeUserRequest.username.get}' already exists") } userUpdatePayload = UserUpdatePayloadADM( @@ -1157,11 +1157,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde def createNewUserTask(createRequest: CreateUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID) = for { // check username _ <- Future(if (createRequest.username.isEmpty) throw BadRequestException("Username cannot be empty")) - _ = stringFormatter.validateUsername(createRequest.username, throw BadRequestException(s"The username: '${createRequest.username}' contains invalid characters")) + _ = stringFormatter.validateUsername(createRequest.username, throw BadRequestException(s"The username '${createRequest.username}' contains invalid characters")) // check email _ = if (createRequest.email.isEmpty) throw BadRequestException("Email cannot be empty") - _ = stringFormatter.validateEmailAndThrow(createRequest.email, throw BadRequestException(s"The email: '${createRequest.email}' is invalid")) + _ = stringFormatter.validateEmailAndThrow(createRequest.email, throw BadRequestException(s"The email '${createRequest.email}' is invalid")) // check other _ = if (createRequest.password.isEmpty) throw BadRequestException("Password cannot be empty") @@ -1170,12 +1170,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde usernameTaken: Boolean <- userByUsernameExists(Some(createRequest.username)) _ = if (usernameTaken) { - throw DuplicateValueException(s"User with the username: '${createRequest.username}' already exists") + throw DuplicateValueException(s"User with the username '${createRequest.username}' already exists") } emailTaken: Boolean <- userByEmailExists(Some(createRequest.email)) _ = if (emailTaken) { - throw DuplicateValueException(s"User with the email: '${createRequest.email}' already exists") + throw DuplicateValueException(s"User with the email '${createRequest.email}' already exists") } userIri = stringFormatter.makeRandomPersonIri @@ -1189,7 +1189,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde triplestore = settings.triplestoreType, userIri = userIri, userClassIri = OntologyConstants.KnoraAdmin.User, - username = stringFormatter.validateAndEscapeUsername(createRequest.username, throw BadRequestException(s"The username: '${createRequest.username}' contains invalid characters")), + username = stringFormatter.validateAndEscapeUsername(createRequest.username, throw BadRequestException(s"The username '${createRequest.username}' contains invalid characters")), email = createRequest.email, password = hashedPassword, givenName = createRequest.givenName, diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala index 9164d33dbb..087ea8d37a 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala @@ -257,7 +257,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.anonymousUser, UUID.randomUUID ) - expectMsg(Failure(DuplicateValueException(s"User with the username: 'root' already exists"))) + expectMsg(Failure(DuplicateValueException(s"User with the username 'root' already exists"))) } "return a 'DuplicateValueException' if the supplied 'email' is not unique" in { @@ -275,7 +275,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.anonymousUser, UUID.randomUUID ) - expectMsg(Failure(DuplicateValueException(s"User with the email: 'root@example.com' already exists"))) + expectMsg(Failure(DuplicateValueException(s"User with the email 'root@example.com' already exists"))) } "return a 'BadRequestException' if the supplied 'username' contains invalid characters (@)" in { @@ -293,7 +293,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.anonymousUser, UUID.randomUUID ) - expectMsg(Failure(BadRequestException(s"The username: 'donald.duck2@example.com' contains invalid characters"))) + expectMsg(Failure(BadRequestException(s"The username 'donald.duck2@example.com' contains invalid characters"))) } "return a 'BadRequestException' if the supplied 'username' contains invalid characters (-)" in { @@ -311,7 +311,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.anonymousUser, UUID.randomUUID ) - expectMsg(Failure(BadRequestException(s"The username: 'donald-duck' contains invalid characters"))) + expectMsg(Failure(BadRequestException(s"The username 'donald-duck' contains invalid characters"))) } "return a 'BadRequestException' if the supplied 'email' is invalid" in { @@ -329,7 +329,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.anonymousUser, UUID.randomUUID ) - expectMsg(Failure(BadRequestException(s"The email: 'root3' is invalid"))) + expectMsg(Failure(BadRequestException(s"The email 'root3' is invalid"))) } } @@ -398,7 +398,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.superUser, UUID.randomUUID ) - expectMsg(Failure(DuplicateValueException(s"User with the username: 'root' already exists"))) + expectMsg(Failure(DuplicateValueException(s"User with the username 'root' already exists"))) } "return a 'DuplicateValueException' if the supplied 'email' is not unique" in { @@ -410,7 +410,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with SharedTestDataADM.superUser, UUID.randomUUID ) - expectMsg(Failure(DuplicateValueException(s"User with the email: 'root@example.com' already exists"))) + expectMsg(Failure(DuplicateValueException(s"User with the email 'root@example.com' already exists"))) } "return 'BadRequest' if the new 'username' contains invalid characters (@)" in { @@ -424,7 +424,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with UUID.randomUUID() ) - expectMsg(timeout, Failure(BadRequestException(s"The username: 'donald.duck2@example.com' contains invalid characters"))) + expectMsg(timeout, Failure(BadRequestException(s"The username 'donald.duck2@example.com' contains invalid characters"))) } "return 'BadRequest' if the new 'username' contains invalid characters (-)" in { @@ -438,7 +438,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with UUID.randomUUID() ) - expectMsg(timeout, Failure(BadRequestException(s"The username: 'donald-duck' contains invalid characters"))) + expectMsg(timeout, Failure(BadRequestException(s"The username 'donald-duck' contains invalid characters"))) } @@ -453,7 +453,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with UUID.randomUUID() ) - expectMsg(timeout, Failure(BadRequestException(s"The email: 'root3' is invalid"))) + expectMsg(timeout, Failure(BadRequestException(s"The email address 'root3' is invalid"))) } "UPDATE the user's password (by himself)" in {