diff --git a/.gitignore b/.gitignore
index af46d9555b..e75f10cb9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,5 +57,6 @@ dump.rdb
dependencies.txt
/client-test-data.zip
/db_staging_dump.trig
-cleandeps.sh
+/.vscode
+/cleandeps.sh
/.metals
diff --git a/webapi/scripts/expected-client-test-data.txt b/webapi/scripts/expected-client-test-data.txt
index 7376daadb8..13d4f03688 100644
--- a/webapi/scripts/expected-client-test-data.txt
+++ b/webapi/scripts/expected-client-test-data.txt
@@ -137,7 +137,11 @@ test-data/admin/users/
test-data/admin/users/add-user-to-group-response.json
test-data/admin/users/add-user-to-project-admin-group-response.json
test-data/admin/users/add-user-to-project-response.json
+test-data/admin/users/create-user-request-duplicate-email.json
+test-data/admin/users/create-user-request-duplicate-username.json
test-data/admin/users/create-user-request.json
+test-data/admin/users/create-user-response-duplicate-email.json
+test-data/admin/users/create-user-response-duplicate-username.json
test-data/admin/users/create-user-response.json
test-data/admin/users/create-user-with-custom-Iri-request.json
test-data/admin/users/create-user-with-custom-Iri-response.json
@@ -153,17 +157,25 @@ test-data/admin/users/get-user-response.json
test-data/admin/users/get-users-for-ProjectAdmin-response.json
test-data/admin/users/get-users-for-SystemAdmin-response.json
test-data/admin/users/get-users-response.json
+test-data/admin/users/incomplete-update-user-password-request-2.json
+test-data/admin/users/incomplete-update-user-password-request.json
+test-data/admin/users/incomplete-update-user-password-response-2.json
+test-data/admin/users/incomplete-update-user-password-response.json
test-data/admin/users/remove-user-from-group-response.json
test-data/admin/users/remove-user-from-project-admin-group-response.json
test-data/admin/users/remove-user-from-project-response.json
test-data/admin/users/update-user-password-request.json
test-data/admin/users/update-user-password-response.json
+test-data/admin/users/update-user-request-without-iri.json
test-data/admin/users/update-user-request.json
+test-data/admin/users/update-user-response-without-iri-1.json
+test-data/admin/users/update-user-response-without-iri-2.json
test-data/admin/users/update-user-response.json
test-data/admin/users/update-user-status-request.json
test-data/admin/users/update-user-status-response.json
test-data/admin/users/update-user-system-admin-membership-request.json
test-data/admin/users/update-user-system-admin-membership-response.json
+test-data/admin/users/user-already-member-of-project-response.json
test-data/system/
test-data/system/health/
test-data/system/health/maintenance-mode-response.json
diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala
index a8a58d51c7..3097a1bd59 100644
--- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala
+++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala
@@ -89,7 +89,7 @@ case class ChangeGroupApiRequestADM(name: Option[String] = None,
if (parametersCount == 0) throw BadRequestException("No data sent in API request.")
/**
- * check that only allowed information for the 2 cases is send and not more.
+ * check that only allowed information for the 2 cases is sent and not more.
*/
// change status case
if (status.isDefined) {
diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/AdminEntities.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/AdminEntities.scala
new file mode 100644
index 0000000000..8f5f8f1d53
--- /dev/null
+++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/AdminEntities.scala
@@ -0,0 +1,72 @@
+package org.knora.webapi.messages.admin.responder.usersmessages
+
+import org.knora.webapi.IRI
+
+sealed trait ValidationError
+case object InvalidUsername extends ValidationError
+case object InvalidEmail extends ValidationError
+case object InvalidGivenOrFamilyName extends ValidationError
+case object InvalidPassword extends ValidationError
+case object InvalidLanguageCode extends ValidationError
+
+trait UserCreatePayloadTraitADM {
+ def create(
+ id: Option[IRI],
+ username: Username,
+ email: Email,
+ givenName: GivenName,
+ familyName: FamilyName,
+ password: Password,
+ status: Status,
+ lang: LanguageCode,
+ systemAdmin: SystemAdmin
+ ): UserCreatePayloadADM
+}
+
+/**
+ * User entity representing the payload for the create user request
+ */
+sealed abstract case class UserCreatePayloadADM(
+ id: Option[IRI],
+ username: Option[Username],
+ email: Option[Email],
+ givenName: Option[GivenName],
+ familyName: Option[FamilyName],
+ password: Option[Password],
+ status: Option[Status],
+ lang: Option[LanguageCode],
+ projects: Option[Seq[IRI]],
+ projectsAdmin: Option[Seq[IRI]],
+ groups: Option[Seq[IRI]],
+ systemAdmin: Option[SystemAdmin]
+)
+
+object UserCreatePayloadADM extends UserCreatePayloadTraitADM {
+
+ /** The create constructor needs all attributes but id which is optional */
+ override def create(
+ id: Option[IRI] = None,
+ username: Username,
+ email: Email,
+ givenName: GivenName,
+ familyName: FamilyName,
+ password: Password,
+ status: Status,
+ lang: LanguageCode,
+ systemAdmin: SystemAdmin
+ ): UserCreatePayloadADM =
+ new UserCreatePayloadADM(
+ id = id,
+ username = Some(username),
+ email = Some(email),
+ givenName = Some(givenName),
+ familyName = Some(familyName),
+ password = Some(password),
+ status = Some(status),
+ lang = Some(lang),
+ projects = None,
+ projectsAdmin = None,
+ groups = None,
+ systemAdmin = Some(systemAdmin)
+ ) {}
+}
diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala
index 5dd282cc91..cbc1da7122 100644
--- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala
+++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala
@@ -19,8 +19,6 @@
package org.knora.webapi.messages.admin.responder.usersmessages
-import java.util.UUID
-
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import org.knora.webapi._
import org.knora.webapi.exceptions.{BadRequestException, DataConversionException, InconsistentRepositoryDataException}
@@ -35,6 +33,8 @@ import org.knora.webapi.messages.v1.responder.usermessages._
import org.knora.webapi.messages.{OntologyConstants, StringFormatter}
import spray.json._
+import java.util.UUID
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// API requests
@@ -63,33 +63,18 @@ case class CreateUserApiRequestADM(
systemAdmin: Boolean
) {
- implicit protected val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance
-
def toJsValue: JsValue = UsersADMJsonProtocol.createUserApiRequestADMFormat.write(this)
-
- // check for required information
- if (username.isEmpty) throw BadRequestException("Username cannot be empty")
- if (email.isEmpty) throw BadRequestException("Email cannot be empty")
- if (password.isEmpty) throw BadRequestException("Password cannot be empty")
- if (givenName.isEmpty) throw BadRequestException("Given name cannot be empty")
- if (familyName.isEmpty) throw BadRequestException("Family name cannot be empty")
-
- //check the custom Iri
- stringFormatter.validateOptionalUserIri(id, throw BadRequestException(s"Invalid user IRI"))
}
/**
* Represents an API request payload that asks the Knora API server to update an existing user. Information that can
- * be changed include the user's username, email, given name, family name, language, password, user status, and system admin
- * membership.
+ * be changed are: user's username, email, given name, family name, language, user status, and system admin membership.
*
* @param username the new username. Needs to be unique on the server.
* @param email the new email address. Needs to be unique on the server.
* @param givenName the new given name.
* @param familyName the new family name.
* @param lang the new ISO 639-1 code of the new preferred language.
- * @param requesterPassword the password of the user making the request.
- * @param newPassword the new password.
* @param status the new user status (active = true, inactive = false).
* @param systemAdmin the new system admin membership status.
*/
@@ -99,8 +84,6 @@ case class ChangeUserApiRequestADM(
givenName: Option[String] = None,
familyName: Option[String] = None,
lang: Option[String] = None,
- requesterPassword: Option[String] = None,
- newPassword: Option[String] = None,
status: Option[Boolean] = None,
systemAdmin: Option[Boolean] = None
) {
@@ -111,49 +94,40 @@ case class ChangeUserApiRequestADM(
givenName,
familyName,
lang,
- requesterPassword,
- newPassword,
status,
systemAdmin
).flatten.size
- // println(requesterPassword + " " + newPassword)
-
// something needs to be sent, i.e. everything 'None' is not allowed
if (parametersCount == 0) throw BadRequestException("No data sent in API request.")
- /* check that only allowed information for the 4 cases is send and not more. */
-
- // change password case
- if (requesterPassword.isDefined || newPassword.isDefined) {
- if (parametersCount > 2) {
- throw BadRequestException("Too many parameters sent for password change.")
- } else if (parametersCount < 2) {
- throw BadRequestException("Too few parameters sent for password change.")
- }
- }
+ /* check that only allowed information for the 3 cases (changing status, systemAdmin and basic information) is sent and not more. */
// change status case
if (status.isDefined) {
- if (parametersCount > 1) throw BadRequestException("Too many parameters sent for user status change.")
+ if (parametersCount > 1) throw BadRequestException("Too many parameters sent for change request.")
}
// change system admin membership case
if (systemAdmin.isDefined) {
- if (parametersCount > 1) throw BadRequestException("Too many parameters sent for system admin membership change.")
+ if (parametersCount > 1) throw BadRequestException("Too many parameters sent for change request.")
}
// change basic user information case
- if (parametersCount > 5) throw BadRequestException("Too many parameters sent for basic user information change.")
+ if (parametersCount > 5) throw BadRequestException("Too many parameters sent for change request.")
def toJsValue: JsValue = UsersADMJsonProtocol.changeUserApiRequestADMFormat.write(this)
}
+case class ChangeUserPasswordApiRequestADM(requesterPassword: Option[String], newPassword: Option[String]) {
+ def toJsValue: JsValue = UsersADMJsonProtocol.changeUserPasswordApiRequestADMFormat.write(this)
+}
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Messages
/**
- * An abstract trait representing message that can be sent to `UsersResponderV1`.
+ * An abstract trait representing message that can be sent to `UsersResponderADM`.
*/
sealed trait UsersResponderRequestADM extends KnoraRequestADM
@@ -172,7 +146,7 @@ case class UsersGetADM(
) extends UsersResponderRequestADM
/**
- * Get all information about all users in form of [[UsersGetResponseV1]]. The UsersGetRequestV1 returns either
+ * Get all information about all users in form of [[UsersGetResponseADM]]. The UsersResponderRequestADM returns either
* something or a NotFound exception if there are no users found. Administration permission checking is performed.
*
* @param userInformationTypeADM the extent of the information returned.
@@ -218,13 +192,13 @@ case class UserGetRequestADM(
/**
* Requests the creation of a new user.
*
- * @param createRequest the [[CreateUserApiRequestADM]] information used for creating the new user.
+ * @param userCreatePayloadADM the [[UserCreatePayloadADM]] information used for creating the new user.
* @param featureFactoryConfig the feature factory configuration.
* @param requestingUser the user creating the new user.
* @param apiRequestID the ID of the API request.
*/
case class UserCreateRequestADM(
- createRequest: CreateUserApiRequestADM,
+ userCreatePayloadADM: UserCreatePayloadADM,
featureFactoryConfig: FeatureFactoryConfig,
requestingUser: UserADM,
apiRequestID: UUID
@@ -234,14 +208,14 @@ case class UserCreateRequestADM(
* Request updating of an existing user.
*
* @param userIri the IRI of the user to be updated.
- * @param changeUserRequest the data which needs to be update.
+ * @param userUpdateBasicInformationPayload the [[UserUpdateBasicInformationPayloadADM]] object containing the data to be updated.
* @param featureFactoryConfig the feature factory configuration.
* @param requestingUser the user initiating the request.
* @param apiRequestID the ID of the API request.
*/
-case class UserChangeBasicUserInformationRequestADM(
+case class UserChangeBasicInformationRequestADM(
userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
+ userUpdateBasicInformationPayload: UserUpdateBasicInformationPayloadADM,
featureFactoryConfig: FeatureFactoryConfig,
requestingUser: UserADM,
apiRequestID: UUID
@@ -251,14 +225,14 @@ case class UserChangeBasicUserInformationRequestADM(
* Request updating the users password.
*
* @param userIri the IRI of the user to be updated.
- * @param changeUserRequest the [[ChangeUserApiRequestADM]] object containing the old and new password.
+ * @param userUpdatePasswordPayload the [[UserUpdatePasswordPayloadADM]] object containing the old and new password.
* @param featureFactoryConfig the feature factory configuration.
* @param requestingUser the user initiating the request.
* @param apiRequestID the ID of the API request.
*/
case class UserChangePasswordRequestADM(
userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
+ userUpdatePasswordPayload: UserUpdatePasswordPayloadADM,
featureFactoryConfig: FeatureFactoryConfig,
requestingUser: UserADM,
apiRequestID: UUID
@@ -268,14 +242,14 @@ case class UserChangePasswordRequestADM(
* Request updating the users status ('knora-base:isActiveUser' property)
*
* @param userIri the IRI of the user to be updated.
- * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing the new status (true / false).
+ * @param status the [[Status]] containing the new status (true / false).
* @param featureFactoryConfig the feature factory configuration.
* @param requestingUser the user initiating the request.
* @param apiRequestID the ID of the API request.
*/
case class UserChangeStatusRequestADM(
userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
+ status: Status,
featureFactoryConfig: FeatureFactoryConfig,
requestingUser: UserADM,
apiRequestID: UUID
@@ -285,15 +259,14 @@ case class UserChangeStatusRequestADM(
* Request updating the users system admin status ('knora-base:isInSystemAdminGroup' property)
*
* @param userIri the IRI of the user to be updated.
- * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing
- * the new system admin membership status (true / false).
+ * @param systemAdmin the [[SystemAdmin]] value object containing the new system admin membership status (true / false).
* @param featureFactoryConfig the feature factory configuration.
* @param requestingUser the user initiating the request.
* @param apiRequestID the ID of the API request.
*/
case class UserChangeSystemAdminMembershipStatusRequestADM(
userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
+ systemAdmin: SystemAdmin,
featureFactoryConfig: FeatureFactoryConfig,
requestingUser: UserADM,
apiRequestID: UUID
@@ -450,7 +423,7 @@ case class UserGroupMembershipRemoveRequestADM(
* @param users a sequence of user profiles of the requested type.
*/
case class UsersGetResponseADM(users: Seq[UserADM]) extends KnoraResponseADM {
- def toJsValue = UsersADMJsonProtocol.usersGetResponseADMFormat.write(this)
+ def toJsValue: JsValue = UsersADMJsonProtocol.usersGetResponseADMFormat.write(this)
}
/**
@@ -553,12 +526,12 @@ case class UserADM(
// SCrypt
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
val encoder = new SCryptPasswordEncoder()
- encoder.matches(password, hashedPassword.toString)
+ encoder.matches(password, hashedPassword)
} else if (hashedPassword.startsWith("$2a$")) {
// BCrypt
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
val encoder = new BCryptPasswordEncoder()
- encoder.matches(password, hashedPassword.toString)
+ encoder.matches(password, hashedPassword)
} else {
// SHA-1
val md = java.security.MessageDigest.getInstance("SHA-1")
@@ -573,7 +546,7 @@ case class UserADM(
*/
def ofType(userTemplateType: UserInformationTypeADM): UserADM =
userTemplateType match {
- case UserInformationTypeADM.PUBLIC => {
+ case UserInformationTypeADM.PUBLIC =>
UserADM(
id = id,
username = "",
@@ -589,9 +562,7 @@ case class UserADM(
sessionId = None,
permissions = PermissionsDataADM()
)
- }
- case UserInformationTypeADM.SHORT => {
-
+ case UserInformationTypeADM.SHORT =>
UserADM(
id = id,
username = username,
@@ -607,9 +578,7 @@ case class UserADM(
sessionId = None,
permissions = PermissionsDataADM()
)
- }
- case UserInformationTypeADM.RESTRICTED => {
-
+ case UserInformationTypeADM.RESTRICTED =>
UserADM(
id = id,
username = username,
@@ -625,8 +594,7 @@ case class UserADM(
sessionId = None,
permissions = permissions
)
- }
- case UserInformationTypeADM.FULL => {
+ case UserInformationTypeADM.FULL =>
UserADM(
id = id,
username = username,
@@ -642,7 +610,6 @@ case class UserADM(
sessionId = sessionId,
permissions = permissions
)
- }
case _ => throw BadRequestException(s"The requested userTemplateType: $userTemplateType is invalid.")
}
@@ -668,8 +635,6 @@ case class UserADM(
def isSystemUser: Boolean = id.equalsIgnoreCase(OntologyConstants.KnoraAdmin.SystemUser)
- def isAnonymousUser: Boolean = id.equalsIgnoreCase(OntologyConstants.KnoraAdmin.AnonymousUser)
-
def fullname: String = givenName + " " + familyName
def getDigest: String = {
@@ -744,6 +709,8 @@ case class UserADM(
status = Some(status),
lang = lang
)
+
+ def isAnonymousUser: Boolean = id.equalsIgnoreCase(OntologyConstants.KnoraAdmin.AnonymousUser)
}
/**
@@ -763,10 +730,10 @@ object UserInformationTypeADM extends Enumeration {
type UserInformationTypeADM = Value
- val PUBLIC = Value(0, "public") // a temporary type which only returns firstname and lastname
- val SHORT = Value(1, "short") // only basic user information (restricted and additionally without groups
- val RESTRICTED = Value(2, "restricted") // without sensitive information
- val FULL = Value(3, "full") // everything, including sensitive information
+ val PUBLIC: Value = Value(0, "public") // a temporary type which only returns firstname and lastname
+ val SHORT: Value = Value(1, "short") // only basic user information (restricted and additionally without groups
+ val RESTRICTED: Value = Value(2, "restricted") // without sensitive information
+ val FULL: Value = Value(3, "full") // everything, including sensitive information
val valueMap: Map[String, Value] = values.map(v => (v.toString, v)).toMap
@@ -791,9 +758,9 @@ object UserIdentifierType extends Enumeration {
type UserIdentifierType
- val IRI = Value(0, "iri")
- val EMAIL = Value(1, "email")
- val USERNAME = Value(3, "username")
+ val IRI: Value = Value(0, "iri")
+ val EMAIL: Value = Value(1, "email")
+ val USERNAME: Value = Value(3, "username")
}
/**
@@ -911,13 +878,12 @@ class UserIdentifierADM private (
}
/**
- * Payload used for updating of an existing user.
+ * Payload used for updating an existing user.
*
- * @param email the new email address. Needs to be unique on the server.
* @param username the new username.
+ * @param email the new email address. Needs to be unique on the server.
* @param givenName the new given name.
* @param familyName the new family name.
- * @param password the new password.
* @param status the new status.
* @param lang the new language.
* @param projects the new project memberships list.
@@ -925,25 +891,24 @@ class UserIdentifierADM private (
* @param groups the new group memberships list.
* @param systemAdmin the new system admin membership
*/
-case class UserUpdatePayloadADM(
- username: Option[String] = None,
- email: Option[String] = None,
- givenName: Option[String] = None,
- familyName: Option[String] = None,
- password: Option[String] = None,
- status: Option[Boolean] = None,
- lang: Option[String] = None,
+case class UserChangeRequestADM(
+ username: Option[Username] = None,
+ email: Option[Email] = None,
+ givenName: Option[GivenName] = None,
+ familyName: Option[FamilyName] = None,
+ status: Option[Status] = None,
+ lang: Option[LanguageCode] = None,
projects: Option[Seq[IRI]] = None,
projectsAdmin: Option[Seq[IRI]] = None,
groups: Option[Seq[IRI]] = None,
- systemAdmin: Option[Boolean] = None
+ systemAdmin: Option[SystemAdmin] = None
) {
val parametersCount: Int = List(
+ username,
email,
givenName,
familyName,
- password,
status,
lang,
projects,
@@ -957,13 +922,6 @@ case class UserUpdatePayloadADM(
throw BadRequestException("No data sent in API request.")
}
- /* check that only allowed information for the 4 cases is send and not more. */
-
- // change password case
- if (password.isDefined && parametersCount > 1) {
- throw BadRequestException("Too many parameters sent for password change.")
- }
-
// change status case
if (status.isDefined && parametersCount > 1) {
throw BadRequestException("Too many parameters sent for user status change.")
@@ -990,12 +948,44 @@ case class UserUpdatePayloadADM(
}
// change basic user information case
- if (parametersCount > 4) {
+ if (parametersCount > 5) {
throw BadRequestException("Too many parameters sent for basic user information change.")
}
+}
+/**
+ * Payload used for updating basic information of an existing user.
+ *
+ * @param username the new username.
+ * @param email the new email address. Needs to be unique on the server.
+ * @param givenName the new given name.
+ * @param familyName the new family name.
+ * @param lang the new language.
+ */
+case class UserUpdateBasicInformationPayloadADM(
+ username: Option[Username] = None,
+ email: Option[Email] = None,
+ givenName: Option[GivenName] = None,
+ familyName: Option[FamilyName] = None,
+ lang: Option[LanguageCode] = None
+) {
+
+ val parametersCount: Int = List(
+ username,
+ email,
+ givenName,
+ familyName,
+ lang
+ ).flatten.size
+
+ // something needs to be sent, i.e. everything 'None' is not allowed
+ if (parametersCount == 0) {
+ throw BadRequestException("No data sent in API request.")
+ }
}
+case class UserUpdatePasswordPayloadADM(requesterPassword: Password, newPassword: Password) {}
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// JSON formatting
@@ -1022,17 +1012,12 @@ object UsersADMJsonProtocol
"lang",
"systemAdmin"
)
- implicit val changeUserApiRequestADMFormat: RootJsonFormat[ChangeUserApiRequestADM] = jsonFormat(
- ChangeUserApiRequestADM,
- "username",
- "email",
- "givenName",
- "familyName",
- "lang",
+ implicit val changeUserApiRequestADMFormat: RootJsonFormat[ChangeUserApiRequestADM] =
+ jsonFormat(ChangeUserApiRequestADM, "username", "email", "givenName", "familyName", "lang", "status", "systemAdmin")
+ implicit val changeUserPasswordApiRequestADMFormat: RootJsonFormat[ChangeUserPasswordApiRequestADM] = jsonFormat(
+ ChangeUserPasswordApiRequestADM,
"requesterPassword",
- "newPassword",
- "status",
- "systemAdmin"
+ "newPassword"
)
implicit val usersGetResponseADMFormat: RootJsonFormat[UsersGetResponseADM] = jsonFormat1(UsersGetResponseADM)
implicit val userProfileResponseADMFormat: RootJsonFormat[UserResponseADM] = jsonFormat1(UserResponseADM)
diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/ValueObjects.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/ValueObjects.scala
new file mode 100644
index 0000000000..70a807dee1
--- /dev/null
+++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/ValueObjects.scala
@@ -0,0 +1,146 @@
+package org.knora.webapi.messages.admin.responder.usersmessages
+
+import org.knora.webapi.LanguageCodes
+import org.knora.webapi.exceptions.BadRequestException
+
+import scala.util.matching.Regex
+
+trait ValueObject[T, K] {
+ def create(value: K): Either[Throwable, T]
+}
+
+/**
+ * Username value object.
+ */
+sealed abstract case class Username(value: String)
+
+object Username extends ValueObject[Username, String] {
+
+ /**
+ * A regex that matches a valid username
+ * - 4 - 50 characters long
+ * - Only contains alphanumeric characters, underscore and dot.
+ * - Underscore and dot can't be at the end or start of a username
+ * - Underscore or dot can't be used multiple times in a row
+ */
+ private val UsernameRegex: Regex =
+ """^(?=.{4,50}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?
+ Right(new Username(value) {})
+ case None => Left(BadRequestException("Invalid username"))
+ }
+ }
+
+}
+
+/**
+ * Email value object.
+ */
+sealed abstract case class Email(value: String)
+
+object Email extends ValueObject[Email, String] {
+
+ private val EmailRegex: Regex = """^.+@.+$""".r // TODO use proper validation
+
+ override def create(value: String): Either[Throwable, Email] =
+ if (value.isEmpty) {
+ Left(BadRequestException("Missing email"))
+ } else {
+ EmailRegex.findFirstIn(value) match {
+ case Some(value) => Right(new Email(value) {})
+ case None => Left(BadRequestException("Invalid email"))
+ }
+ }
+}
+
+/**
+ * Password value object.
+ */
+sealed abstract case class Password(value: String)
+
+object Password extends ValueObject[Password, String] {
+
+ private val PasswordRegex: Regex = """^[\s\S]*$""".r //TODO: add password validation
+
+ override def create(value: String): Either[Throwable, Password] =
+ if (value.isEmpty) {
+ Left(BadRequestException("Missing password"))
+ } else {
+ PasswordRegex.findFirstIn(value) match {
+ case Some(value) => Right(new Password(value) {})
+ case None => Left(BadRequestException("Invalid password"))
+ }
+ }
+}
+
+/**
+ * GivenName value object.
+ */
+sealed abstract case class GivenName(value: String)
+
+object GivenName extends ValueObject[GivenName, String] {
+ // TODO use proper validation for value
+ override def create(value: String): Either[Throwable, GivenName] =
+ if (value.isEmpty) {
+ Left(BadRequestException("Missing given name"))
+ } else {
+ Right(new GivenName(value) {})
+ }
+}
+
+/**
+ * FamilyName value object.
+ */
+sealed abstract case class FamilyName(value: String)
+
+object FamilyName extends ValueObject[FamilyName, String] {
+ // TODO use proper validation for value
+ override def create(value: String): Either[Throwable, FamilyName] =
+ if (value.isEmpty) {
+ Left(BadRequestException("Missing family name"))
+ } else {
+ Right(new FamilyName(value) {})
+ }
+}
+
+/**
+ * LanguageCode value object.
+ */
+sealed abstract case class LanguageCode(value: String)
+
+object LanguageCode extends ValueObject[LanguageCode, String] {
+ override def create(value: String): Either[Throwable, LanguageCode] =
+ if (value.isEmpty) {
+ Left(BadRequestException("Missing language code"))
+ } else if (!LanguageCodes.SupportedLanguageCodes.contains(value)) {
+ Left(BadRequestException("Invalid language code"))
+ } else {
+ Right(new LanguageCode(value) {})
+ }
+}
+
+/**
+ * Status value object.
+ */
+sealed abstract case class Status(value: Boolean)
+
+object Status extends ValueObject[Status, Boolean] {
+ override def create(value: Boolean): Either[Throwable, Status] =
+ Right(new Status(value) {})
+}
+
+/**
+ * SystemAdmin value object.
+ */
+sealed abstract case class SystemAdmin(value: Boolean)
+
+object SystemAdmin extends ValueObject[SystemAdmin, Boolean] {
+ override def create(value: Boolean): Either[Throwable, SystemAdmin] =
+ Right(new SystemAdmin(value) {})
+}
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 00c1dafd67..ba2cc76954 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
@@ -19,11 +19,10 @@
package org.knora.webapi.responders.admin
-import java.util.UUID
-
import akka.http.scaladsl.util.FastFuture
import akka.pattern._
-import org.knora.webapi.exceptions._
+import org.knora.webapi._
+import org.knora.webapi.exceptions.{BadRequestException, InconsistentRepositoryDataException, _}
import org.knora.webapi.feature.FeatureFactoryConfig
import org.knora.webapi.instrumentation.InstrumentationSupport
import org.knora.webapi.messages.IriConversions._
@@ -31,7 +30,7 @@ import org.knora.webapi.messages.admin.responder.groupsmessages.{GroupADM, Group
import org.knora.webapi.messages.admin.responder.permissionsmessages.{PermissionDataGetADM, PermissionsDataADM}
import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetADM, ProjectIdentifierADM}
import org.knora.webapi.messages.admin.responder.usersmessages.UserInformationTypeADM.UserInformationTypeADM
-import org.knora.webapi.messages.admin.responder.usersmessages.{UserUpdatePayloadADM, _}
+import org.knora.webapi.messages.admin.responder.usersmessages.{Password, UserChangeRequestADM, _}
import org.knora.webapi.messages.store.cacheservicemessages.{
CacheServiceGetUserADM,
CacheServicePutUserADM,
@@ -44,22 +43,22 @@ import org.knora.webapi.messages.v1.responder.usermessages._
import org.knora.webapi.messages.{OntologyConstants, SmartIri}
import org.knora.webapi.responders.Responder.handleUnexpectedMessage
import org.knora.webapi.responders.{IriLocker, Responder}
-import org.knora.webapi.{exceptions, _}
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import java.util.UUID
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 [[UsersResponderRequestADM]], and returns an appropriate message.
+ */
def receive(msg: UsersResponderRequestADM) = msg match {
case UsersGetADM(userInformationTypeADM, featureFactoryConfig, requestingUser) =>
getAllUserADM(userInformationTypeADM, featureFactoryConfig, requestingUser)
@@ -69,56 +68,82 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
getSingleUserADM(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser)
case UserGetRequestADM(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser) =>
getSingleUserADMRequest(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser)
- case UserCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) =>
- createNewUserADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID)
- case UserChangeBasicUserInformationRequestADM(userIri,
- changeUserRequest,
- featureFactoryConfig,
- requestingUser,
- apiRequestID) =>
- changeBasicUserInformationADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID)
- case UserChangePasswordRequestADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) =>
- changePasswordADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID)
- case UserChangeStatusRequestADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) =>
- changeUserStatusADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID)
- case UserChangeSystemAdminMembershipStatusRequestADM(userIri,
- changeSystemAdminMembershipStatusRequest,
- featureFactoryConfig,
- requestingUser,
- apiRequestID) =>
- changeUserSystemAdminMembershipStatusADM(userIri,
- changeSystemAdminMembershipStatusRequest,
- featureFactoryConfig,
- requestingUser,
- apiRequestID)
+ case UserCreateRequestADM(userCreatePayloadADM, featureFactoryConfig, requestingUser, apiRequestID) =>
+ createNewUserADM(userCreatePayloadADM, featureFactoryConfig, requestingUser, apiRequestID)
+ case UserChangeBasicInformationRequestADM(
+ userIri,
+ userUpdateBasicInformationPayload,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
+ changeBasicUserInformationADM(
+ userIri,
+ userUpdateBasicInformationPayload,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ )
+ case UserChangePasswordRequestADM(
+ userIri,
+ userUpdatePasswordPayload,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
+ changePasswordADM(userIri, userUpdatePasswordPayload, featureFactoryConfig, requestingUser, apiRequestID)
+ case UserChangeStatusRequestADM(userIri, status, featureFactoryConfig, requestingUser, apiRequestID) =>
+ changeUserStatusADM(userIri, status, featureFactoryConfig, requestingUser, apiRequestID)
+ case UserChangeSystemAdminMembershipStatusRequestADM(
+ userIri,
+ changeSystemAdminMembershipStatusRequest,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
+ changeUserSystemAdminMembershipStatusADM(
+ userIri,
+ changeSystemAdminMembershipStatusRequest,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ )
case UserProjectMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) =>
userProjectMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser)
case UserProjectMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) =>
userProjectMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID)
- case UserProjectMembershipRemoveRequestADM(userIri,
- projectIri,
- featureFactoryConfig,
- requestingUser,
- apiRequestID) =>
+ case UserProjectMembershipRemoveRequestADM(
+ userIri,
+ projectIri,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
userProjectMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID)
case UserProjectAdminMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser, apiRequestID) =>
userProjectAdminMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser, apiRequestID)
- case UserProjectAdminMembershipAddRequestADM(userIri,
- projectIri,
- featureFactoryConfig,
- requestingUser,
- apiRequestID) =>
+ case UserProjectAdminMembershipAddRequestADM(
+ userIri,
+ projectIri,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
userProjectAdminMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID)
- case UserProjectAdminMembershipRemoveRequestADM(userIri,
- projectIri,
- featureFactoryConfig,
- requestingUser,
- apiRequestID) =>
- userProjectAdminMembershipRemoveRequestADM(userIri,
- projectIri,
- featureFactoryConfig,
- requestingUser,
- apiRequestID)
+ case UserProjectAdminMembershipRemoveRequestADM(
+ userIri,
+ projectIri,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ ) =>
+ userProjectAdminMembershipRemoveRequestADM(
+ userIri,
+ projectIri,
+ featureFactoryConfig,
+ requestingUser,
+ apiRequestID
+ )
case UserGroupMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) =>
userGroupMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser)
case UserGroupMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) =>
@@ -129,1490 +154,1642 @@ 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 featureFactoryConfig the feature factory configuration.
- * @param requestingUser the user initiating the request.
- * @return all the users as a sequence of [[UserADM]].
- */
- private def getAllUserADM(userInformationType: UserInformationTypeADM,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[Seq[UserADM]] = {
-
- //log.debug("getAllUserADM")
-
+ * Gets all the users and returns them as a sequence of [[UserADM]].
+ *
+ * @param userInformationType the extent of the information returned.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the user initiating the request.
+ * @return all the users as a sequence of [[UserADM]].
+ */
+ private def getAllUserADM(
+ userInformationType: UserInformationTypeADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[Seq[UserADM]] =
for {
_ <- Future(
- if (!requestingUser.permissions.isSystemAdmin && !requestingUser.permissions
- .isProjectAdminInAnyProject() && !requestingUser.isSystemUser) {
- throw ForbiddenException("ProjectAdmin or SystemAdmin permissions are required.")
- }
- )
+ if (
+ !requestingUser.permissions.isSystemAdmin && !requestingUser.permissions
+ .isProjectAdminInAnyProject() && !requestingUser.isSystemUser
+ ) {
+ throw ForbiddenException("ProjectAdmin or SystemAdmin permissions are required.")
+ }
+ )
sparqlQueryString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .getUsers(
- triplestore = settings.triplestoreType,
- maybeIri = None,
- maybeUsername = None,
- maybeEmail = None
- )
- .toString())
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .getUsers(
+ triplestore = settings.triplestoreType,
+ maybeIri = None,
+ maybeUsername = None,
+ maybeEmail = None
+ )
+ .toString()
+ )
usersResponse <- (storeManager ? SparqlExtendedConstructRequest(
- sparql = sparqlQueryString,
- featureFactoryConfig = featureFactoryConfig
- )).mapTo[SparqlExtendedConstructResponse]
+ sparql = sparqlQueryString,
+ featureFactoryConfig = featureFactoryConfig
+ )).mapTo[SparqlExtendedConstructResponse]
statements = usersResponse.statements.toList
- // _ = log.debug("getAllUserADM - statements: {}", statements)
-
- users: Seq[UserADM] = statements.map {
- case (userIri: SubjectV2, propsMap: Map[SmartIri, Seq[LiteralV2]]) =>
- UserADM(
- id = userIri.toString,
- username = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Username.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'username' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- email = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Email.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'email' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- givenName = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.GivenName.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'givenName' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- familyName = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.FamilyName.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'familyName' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- status = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Status.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'status' defined."))
- .head
- .asInstanceOf[BooleanLiteralV2]
- .value,
- lang = propsMap
- .getOrElse(
- OntologyConstants.KnoraAdmin.PreferredLanguage.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'preferedLanguage' defined.")
- )
- .head
- .asInstanceOf[StringLiteralV2]
- .value
- )
- }
+ users: Seq[UserADM] = statements.map { case (userIri: SubjectV2, propsMap: Map[SmartIri, Seq[LiteralV2]]) =>
+ UserADM(
+ id = userIri.toString,
+ username = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Username.toSmartIri,
+ throw InconsistentRepositoryDataException(
+ s"User: $userIri has no 'username' defined."
+ )
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ email = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Email.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'email' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ givenName = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.GivenName.toSmartIri,
+ throw InconsistentRepositoryDataException(
+ s"User: $userIri has no 'givenName' defined."
+ )
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ familyName = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.FamilyName.toSmartIri,
+ throw InconsistentRepositoryDataException(
+ s"User: $userIri has no 'familyName' defined."
+ )
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ status = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Status.toSmartIri,
+ throw InconsistentRepositoryDataException(
+ s"User: $userIri has no 'status' defined."
+ )
+ )
+ .head
+ .asInstanceOf[BooleanLiteralV2]
+ .value,
+ lang = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.PreferredLanguage.toSmartIri,
+ throw InconsistentRepositoryDataException(
+ s"User: $userIri has no 'preferedLanguage' defined."
+ )
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value
+ )
+ }
} yield users.sorted
- }
/**
- * Gets all the users and returns them as a [[UsersGetResponseADM]].
- *
- * @param userInformationType the extent of the information returned.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the user initiating the request.
- * @return all the users as a [[UsersGetResponseV1]].
- */
- private def getAllUserADMRequest(userInformationType: UserInformationTypeADM,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[UsersGetResponseADM] = {
+ * Gets all the users and returns them as a [[UsersGetResponseADM]].
+ *
+ * @param userInformationType the extent of the information returned.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the user initiating the request.
+ * @return all the users as a [[UsersGetResponseV1]].
+ */
+ private def getAllUserADMRequest(
+ userInformationType: UserInformationTypeADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[UsersGetResponseADM] =
for {
maybeUsersListToReturn <- getAllUserADM(
- userInformationType = userInformationType,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ userInformationType = userInformationType,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
result = maybeUsersListToReturn match {
- case users: Seq[UserADM] if users.nonEmpty =>
- UsersGetResponseADM(users = users)
- case _ =>
- throw NotFoundException(s"No users found")
- }
+ case users: Seq[UserADM] if users.nonEmpty =>
+ UsersGetResponseADM(users = users)
+ case _ =>
+ throw NotFoundException(s"No users found")
+ }
} yield result
- }
/**
- * ~ 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- skipCache: Boolean = false): Future[Option[UserADM]] = tracedFuture("admin-get-user") {
-
- log.debug(s"getSingleUserADM - id: {}, type: {}, requester: {}, skipCache: {}",
- identifier.value,
- userInformationType,
- requestingUser.username,
- skipCache)
+ * ~ 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 featureFactoryConfig the feature factory configuration.
+ * @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,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ skipCache: Boolean = false
+ ): Future[Option[UserADM]] = tracedFuture("admin-get-user") {
+
+ log.debug(
+ s"getSingleUserADM - id: {}, type: {}, requester: {}, skipCache: {}",
+ identifier.value,
+ userInformationType,
+ requestingUser.username,
+ skipCache
+ )
for {
maybeUserADM <- if (skipCache) {
- // getting directly from triplestore
- getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig)
- } else {
- // getting from cache or triplestore
- getUserFromCacheOrTriplestore(identifier, featureFactoryConfig)
- }
+ // getting directly from triplestore
+ getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig)
+ } else {
+ // getting from cache or triplestore
+ getUserFromCacheOrTriplestore(identifier, featureFactoryConfig)
+ }
// return the correct amount of information depending on either the request or user permission
- finalResponse: Option[UserADM] = if (requestingUser.permissions.isSystemAdmin || requestingUser
- .isSelf(identifier) || requestingUser.isSystemUser) {
- // return everything or what was requested
- maybeUserADM.map(user => user.ofType(userInformationType))
- } else {
- // return only public information
- maybeUserADM.map(user => user.ofType(UserInformationTypeADM.PUBLIC))
- }
+ finalResponse: Option[UserADM] = if (
+ requestingUser.permissions.isSystemAdmin || requestingUser
+ .isSelf(identifier) || requestingUser.isSystemUser
+ ) {
+ // return everything or what was requested
+ maybeUserADM.map(user => user.ofType(userInformationType))
+ } else {
+ // return only public information
+ maybeUserADM.map(user => user.ofType(UserInformationTypeADM.PUBLIC))
+ }
_ = if (finalResponse.nonEmpty) {
- log.debug("getSingleUserADM - successfully retrieved user: {}", identifier.value)
- } else {
- log.debug("getSingleUserADM - could not retrieve user: {}", identifier.value)
- }
+ log.debug("getSingleUserADM - successfully retrieved user: {}", identifier.value)
+ } else {
+ log.debug("getSingleUserADM - could not retrieve user: {}", identifier.value)
+ }
} yield finalResponse
}
/**
- * 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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[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,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[UserResponseADM] =
for {
maybeUserADM <- getSingleUserADM(
- identifier = identifier,
- userInformationType = userInformationType,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ identifier = identifier,
+ userInformationType = userInformationType,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
result = maybeUserADM match {
- case Some(user) => UserResponseADM(user = user)
- case None => throw NotFoundException(s"User '${identifier.value}' not found")
- }
+ case Some(user) => UserResponseADM(user = user)
+ case None => throw NotFoundException(s"User '${identifier.value}' not found")
+ }
} yield result
- }
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- //log.debug(s"changeBasicUserDataV1: changeUserRequest: {}", changeUserRequest)
+ * 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 userUpdateBasicInformationPayload the updated information stored as [[UserUpdateBasicInformationPayloadADM]].
+ * @param featureFactoryConfig the feature factory configuration.
+ * @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,
+ userUpdateBasicInformationPayload: UserUpdateBasicInformationPayloadADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
+
+ log.debug(s"changeBasicUserInformationADM: changeUserRequest: {}", userUpdateBasicInformationPayload)
/**
- * The actual change basic user data task run with an IRI lock.
- */
- def changeBasicUserDataTask(userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * The actual change basic user data task run with an IRI lock.
+ */
+ def changeBasicUserDataTask(
+ userIri: IRI,
+ userUpdateBasicInformationPayload: UserUpdateBasicInformationPayloadADM,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] =
for {
-
- // check if the requesting user is allowed to perform updates
+ // check if the requesting user is allowed to perform updates (i.e. requesting updates own information or is system admin)
_ <- Future(
- if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
- // not the user or a system admin
- //log.debug("same user: {}, system admin: {}", userProfile.userData.user_id.contains(userIri), userProfile.permissionData.isSystemAdmin)
- throw ForbiddenException(
- "User information can only be changed by the user itself or a system administrator")
- }
- )
-
- // check if necessary information is present
- _ = if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
-
- parametersCount = List(changeUserRequest.username,
- changeUserRequest.email,
- changeUserRequest.givenName,
- changeUserRequest.familyName,
- changeUserRequest.lang).flatten.size
- _ = 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.")
+ if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User information can only be changed by the user itself or a system administrator"
+ )
+ }
+ )
// get current user information
currentUserInformation: Option[UserADM] <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- userInformationType = UserInformationTypeADM.FULL,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
-
- // check if user exists
- _ = if (currentUserInformation.isEmpty) {
- throw BadRequestException(s"User ${userIri} does not exist")
- }
-
- // check if we want to change the email
- emailTaken: Boolean <- userByEmailExists(changeUserRequest.email, Some(currentUserInformation.get.email))
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ userInformationType = UserInformationTypeADM.FULL,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
+
+ // check if email is unique in case of a change email request
+ emailTaken: Boolean <-
+ userByEmailExists(userUpdateBasicInformationPayload.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 '${userUpdateBasicInformationPayload.email.get.value}' already exists"
+ )
+ }
- // check if we want to change the username
- usernameTaken: Boolean <- userByUsernameExists(changeUserRequest.username,
- Some(currentUserInformation.get.username))
+ // check if username is unique in case of a change username request
+ usernameTaken: Boolean <-
+ userByUsernameExists(userUpdateBasicInformationPayload.username, Some(currentUserInformation.get.username))
_ = if (usernameTaken) {
- throw DuplicateValueException(s"User with the username '${changeUserRequest.username.get}' already exists")
- }
-
- userUpdatePayload = UserUpdatePayloadADM(
- username = changeUserRequest.username,
- email = changeUserRequest.email,
- givenName = changeUserRequest.givenName,
- familyName = changeUserRequest.familyName,
- lang = changeUserRequest.lang
- )
+ throw DuplicateValueException(
+ s"User with the username '${userUpdateBasicInformationPayload.username.get.value}' already exists"
+ )
+ }
// send change request as SystemUser
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(
+ username = userUpdateBasicInformationPayload.username,
+ email = userUpdateBasicInformationPayload.email,
+ givenName = userUpdateBasicInformationPayload.givenName,
+ familyName = userUpdateBasicInformationPayload.familyName,
+ lang = userUpdateBasicInformationPayload.lang
+ ),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
- // run the user update with an global IRI lock
- taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- USERS_GLOBAL_LOCK_IRI,
- () => changeBasicUserDataTask(userIri, changeUserRequest, requestingUser, apiRequestID)
- )
+ // run the user update with a global IRI lock
+ taskResult <-
+ IriLocker.runWithIriLock(
+ apiRequestID,
+ USERS_GLOBAL_LOCK_IRI,
+ () => changeBasicUserDataTask(userIri, userUpdateBasicInformationPayload, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- log.debug(s"changePasswordADM - userIri: {}", userIri)
- log.debug(s"changePasswordADM - changeUserRequest: {}", changeUserRequest)
- log.debug(s"changePasswordADM - requestingUser: {}", requestingUser)
+ * 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 userUpdatePasswordPayload the current password of the requesting user and the new password.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @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,
+ userUpdatePasswordPayload: UserUpdatePasswordPayloadADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual change password task run with an IRI lock.
- */
- def changePasswordTask(userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * The actual change password task run with an IRI lock.
+ */
+ def changePasswordTask(
+ userIri: IRI,
+ userUpdatePasswordPayload: UserUpdatePasswordPayloadADM,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] =
for {
-
- // check if necessary information is present
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty"))
- _ = if (changeUserRequest.requesterPassword.isEmpty || changeUserRequest.newPassword.isEmpty)
- throw BadRequestException("The user's old and new password need to be both supplied")
-
- // check if the requesting user is allowed to perform password change. it needs to be either the user himself, or a system admin
- _ = if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
- // not the user or system admin
- throw ForbiddenException("User's password can only be changed by the user itself or a system admin.")
- }
+ // check if the requesting user is allowed to perform updates (i.e. requesting updates own information or is system admin)
+ _ <- Future(
+ if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User's password can only be changed by the user itself or a system administrator"
+ )
+ }
+ )
// check if supplied password matches requesting user's password
- _ = log.debug(s"changePasswordADM - requesterPassword: {}", changeUserRequest.requesterPassword.get)
- _ = if (!requestingUser.passwordMatch(changeUserRequest.requesterPassword.get)) {
- throw ForbiddenException("The supplied password does not match the requesting user's password.")
- }
+ _ = if (!requestingUser.passwordMatch(userUpdatePasswordPayload.requesterPassword.value)) {
+ throw ForbiddenException("The supplied password does not match the requesting user's password.")
+ }
- // create the update request
+ // hash the new password
encoder = new BCryptPasswordEncoder(settings.bcryptPasswordStrength)
- newHashedPassword = encoder.encode(changeUserRequest.newPassword.get)
- userUpdatePayload = UserUpdatePayloadADM(password = Some(newHashedPassword))
+ newHashedPassword = Password
+ .create(encoder.encode(userUpdatePasswordPayload.newPassword.value))
+ .fold(error => throw error, value => value)
// update the users password as SystemUser
- result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ result <- updateUserPasswordADM(
+ userIri = userIri,
+ password = newHashedPassword,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the change password task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => changePasswordTask(userIri, changeUserRequest, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => changePasswordTask(userIri, userUpdatePasswordPayload, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- log.debug(s"changeUserStatusADM - changeUserRequest: {}", changeUserRequest)
+ * Change the user's status (active / inactive).
+ *
+ * @param userIri the IRI of the existing user that we want to update.
+ * @param status the new status.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @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,
+ status: Status,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
+
+ log.debug(s"changeUserStatusADM - new status: {}", status)
/**
- * The actual change user status task run with an IRI lock.
- */
- def changeUserStatusTask(userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * The actual change user status task run with an IRI lock.
+ */
+ def changeUserStatusTask(
+ userIri: IRI,
+ status: Status,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] =
for {
-
- _ <- Future(
- // check if necessary information is present
- if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
- )
- _ = if (changeUserRequest.status.isEmpty) throw BadRequestException("New user status cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
- // not the user or a system admin
- // log.debug("same user: {}, system admin: {}", userProfile.userData.user_id.contains(userIri), userProfile.permissionData.isSystemAdmin)
- throw ForbiddenException("User's status can only be changed by the user itself or a system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. requesting updates own information or is system admin)
+ _ <-
+ Future(
+ if (!requestingUser.id.equalsIgnoreCase(userIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException("User's status can only be changed by the user itself or a system administrator")
+ }
+ )
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(status = changeUserRequest.status)
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(status = Some(status)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the change status task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => changeUserStatusTask(userIri, changeUserRequest, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => changeUserStatusTask(userIri, status, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- //log.debug(s"changeUserSystemAdminMembershipStatusV1: changeUserRequest: {}", changeUserRequest)
+ * Change the user's system admin membership status (active / inactive).
+ *
+ * @param userIri the IRI of the existing user that we want to update.
+ * @param systemAdmin the new status.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @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,
+ systemAdmin: SystemAdmin,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual change user status task run with an IRI lock.
- */
- def changeUserSystemAdminMembershipStatusTask(userIri: IRI,
- changeUserRequest: ChangeUserApiRequestADM,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * The actual change user status task run with an IRI lock.
+ */
+ def changeUserSystemAdminMembershipStatusTask(
+ userIri: IRI,
+ systemAdmin: SystemAdmin,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] =
for {
-
- // check if necessary information is present
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty"))
- _ = if (changeUserRequest.systemAdmin.isEmpty)
- throw BadRequestException("New user system admin membership status cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isSystemAdmin) {
- // not a system admin
- // log.debug("system admin: {}", userProfile.permissionData.isSystemAdmin)
- throw ForbiddenException("User's system admin membership can only be changed by a system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. system admin)
+ _ <-
+ Future(
+ if (!requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException("User's system admin membership can only be changed by a system administrator")
+ }
+ )
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(systemAdmin = changeUserRequest.systemAdmin)
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(systemAdmin = Some(systemAdmin)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the change status task with an IRI lock
- taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => changeUserSystemAdminMembershipStatusTask(userIri, changeUserRequest, requestingUser, apiRequestID)
- )
+ taskResult <-
+ IriLocker.runWithIriLock(
+ apiRequestID,
+ userIri,
+ () => changeUserSystemAdminMembershipStatusTask(userIri, systemAdmin, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * Returns user's project memberships as a sequence of [[ProjectADM]].
- *
- * @param userIri the IRI of the user.
- * @param requestingUser the requesting user.
- * @return a sequence of [[ProjectADM]]
- */
- private def userProjectMembershipsGetADM(userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[Seq[ProjectADM]] = {
+ * Returns user's project memberships as a sequence of [[ProjectADM]].
+ *
+ * @param userIri the IRI of the user.
+ * @param requestingUser the requesting user.
+ * @return a sequence of [[ProjectADM]]
+ */
+ private def userProjectMembershipsGetADM(
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[Seq[ProjectADM]] =
for {
maybeUser <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- userInformationType = UserInformationTypeADM.FULL,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ userInformationType = UserInformationTypeADM.FULL,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
result = maybeUser match {
- case Some(userADM) => userADM.projects
- case None => Seq.empty[ProjectADM]
- }
+ case Some(userADM) => userADM.projects
+ case None => Seq.empty[ProjectADM]
+ }
- // _ = log.debug("userProjectMembershipsGetADM - userIri: {}, projects: {}", userIri, result)
} yield result
- }
/**
- * Returns the user's project memberships as [[UserProjectMembershipsGetResponseADM]].
- *
- * @param userIri the user's IRI.
- * @param requestingUser the requesting user.
- * @return a [[UserProjectMembershipsGetResponseADM]].
- */
+ * Returns the user's project memberships as [[UserProjectMembershipsGetResponseADM]].
+ *
+ * @param userIri the user's IRI.
+ * @param requestingUser the requesting user.
+ * @return a [[UserProjectMembershipsGetResponseADM]].
+ */
private def userProjectMembershipsGetRequestADM(
- userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[UserProjectMembershipsGetResponseADM] = {
-
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[UserProjectMembershipsGetResponseADM] =
for {
userExists <- userExists(userIri)
_ = if (!userExists) {
- throw BadRequestException(s"User $userIri does not exist.")
- }
+ throw BadRequestException(s"User $userIri does not exist.")
+ }
projects: Seq[ProjectADM] <- userProjectMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
result = UserProjectMembershipsGetResponseADM(projects = projects)
} yield result
- }
/**
- * Adds a user to a project.
- *
- * @param userIri the user's IRI.
- * @param projectIri the project's IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return
- */
- private def userProjectMembershipAddRequestADM(userIri: IRI,
- projectIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
+ * Adds a user to a project.
+ *
+ * @param userIri the user's IRI.
+ * @param projectIri the project's IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return
+ */
+ private def userProjectMembershipAddRequestADM(
+ userIri: IRI,
+ projectIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
log.debug(s"userProjectMembershipAddRequestADM: userIri: {}, projectIri: {}", userIri, projectIri)
/**
- * The actual task run with an IRI lock.
- */
- def userProjectMembershipAddRequestTask(userIri: IRI,
- projectIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (projectIri.isEmpty) throw BadRequestException("Project IRI cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
- // not a project or system admin
- // log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException("User's project membership can only be changed by a project or system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. is project or system admin)
+ _ <-
+ Future(
+ if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User's project membership can only be changed by a project or system administrator"
+ )
+ }
+ )
// check if user exists
userExists <- userExists(userIri)
- _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
+ _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
// check if project exists
projectExists <- projectExists(projectIri)
- _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
+ _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
// get users current project membership list
currentProjectMemberships <- userProjectMembershipsGetRequestADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
currentProjectMembershipIris: Seq[IRI] = currentProjectMemberships.projects.map(_.id)
// check if user is already member and if not then append to list
updatedProjectMembershipIris = if (!currentProjectMembershipIris.contains(projectIri)) {
- currentProjectMembershipIris :+ projectIri
- } else {
- throw BadRequestException(s"User $userIri is already member of project $projectIri.")
- }
+ currentProjectMembershipIris :+ projectIri
+ } else {
+ throw BadRequestException(
+ s"User $userIri is already member of project $projectIri."
+ )
+ }
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(projects = Some(updatedProjectMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(projects = Some(updatedProjectMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userProjectMembershipAddRequestTask(userIri, projectIri, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => userProjectMembershipAddRequestTask(userIri, projectIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * Removes a user from a project.
- *
- * @param userIri the user's IRI.
- * @param projectIri the project's IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return
- */
- private def userProjectMembershipRemoveRequestADM(userIri: IRI,
- projectIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- // log.debug(s"userProjectMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri)
+ * Removes a user from a project.
+ *
+ * @param userIri the user's IRI.
+ * @param projectIri the project's IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return
+ */
+ private def userProjectMembershipRemoveRequestADM(
+ userIri: IRI,
+ projectIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual task run with an IRI lock.
- */
- def userProjectMembershipRemoveRequestTask(userIri: IRI,
- projectIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (projectIri.isEmpty) throw BadRequestException("Project IRI cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
- // not a project or system admin
- // log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException("User's project membership can only be changed by a project or system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. is project or system admin)
+ _ <-
+ Future(
+ if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User's project membership can only be changed by a project or system administrator"
+ )
+ }
+ )
// check if user exists
userExists <- userExists(userIri)
- _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
+ _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
// check if project exists
projectExists <- projectExists(projectIri)
- _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
+ _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
// get users current project membership list
currentProjectMemberships <- userProjectMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
currentProjectMembershipIris = currentProjectMemberships.map(_.id)
// check if user is not already a member and if he is then remove the project from to list
updatedProjectMembershipIris = if (currentProjectMembershipIris.contains(projectIri)) {
- currentProjectMembershipIris diff Seq(projectIri)
- } else {
- throw BadRequestException(s"User $userIri is not member of project $projectIri.")
- }
+ currentProjectMembershipIris diff Seq(projectIri)
+ } else {
+ throw BadRequestException(
+ s"User $userIri is not member of project $projectIri."
+ )
+ }
// create the update request by using the SystemUser
- userUpdatePayload = UserUpdatePayloadADM(projects = Some(updatedProjectMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(projects = Some(updatedProjectMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userProjectMembershipRemoveRequestTask(userIri, projectIri, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => userProjectMembershipRemoveRequestTask(userIri, projectIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * Returns the user's project admin group memberships as a sequence of [[IRI]]
- *
- * @param userIri the user's IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return a [[UserProjectMembershipsGetResponseV1]].
- */
- private def userProjectAdminMembershipsGetADM(userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[Seq[ProjectADM]] = {
-
+ * Returns the user's project admin group memberships as a sequence of [[IRI]]
+ *
+ * @param userIri the user's IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return a [[UserProjectMembershipsGetResponseV1]].
+ */
+ private def userProjectAdminMembershipsGetADM(
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[Seq[ProjectADM]] =
// ToDo: only allow system user
// ToDo: this is a bit of a hack since the ProjectAdmin group doesn't really exist.
-
for {
sparqlQueryString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.v1.txt
- .getUserByIri(
- triplestore = settings.triplestoreType,
- userIri = userIri
- )
- .toString())
-
- //_ = log.debug("userDataByIRIGetV1 - sparqlQueryString: {}", sparqlQueryString)
+ org.knora.webapi.messages.twirl.queries.sparql.v1.txt
+ .getUserByIri(
+ triplestore = settings.triplestoreType,
+ userIri = userIri
+ )
+ .toString()
+ )
userDataQueryResponse <- (storeManager ? SparqlSelectRequest(sparqlQueryString)).mapTo[SparqlSelectResult]
groupedUserData: Map[String, Seq[String]] = userDataQueryResponse.results.bindings.groupBy(_.rowMap("p")).map {
- case (predicate, rows) => predicate -> rows.map(_.rowMap("o"))
- }
+ case (predicate, rows) => predicate -> rows.map(_.rowMap("o"))
+ }
/* the projects the user is member of */
projectIris: Seq[IRI] = groupedUserData.get(OntologyConstants.KnoraAdmin.IsInProjectAdminGroup) match {
- case Some(projects) => projects
- case None => Seq.empty[IRI]
- }
+ case Some(projects) => projects
+ case None => Seq.empty[IRI]
+ }
maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { projectIri =>
- (responderManager ? ProjectGetADM(
- identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[Option[ProjectADM]]
- }
+ (responderManager ? ProjectGetADM(
+ identifier =
+ ProjectIdentifierADM(maybeIri = Some(projectIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )).mapTo[Option[ProjectADM]]
+ }
maybeProjects: Seq[Option[ProjectADM]] <- Future.sequence(maybeProjectFutures)
- projects: Seq[ProjectADM] = maybeProjects.flatten
+ projects: Seq[ProjectADM] = maybeProjects.flatten
- // _ = log.debug("userProjectAdminMembershipsGetRequestV1 - userIri: {}, projectIris: {}", userIri, projectIris)
} yield projects
- }
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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 featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return a [[UserProjectMembershipsGetResponseV1]].
+ */
private def userProjectAdminMembershipsGetRequestADM(
- userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserProjectAdminMembershipsGetResponseADM] = {
-
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserProjectAdminMembershipsGetResponseADM] =
// ToDo: which user is allowed to do this operation?
// ToDo: check permissions
-
for {
userExists <- userExists(userIri)
_ = if (!userExists) {
- throw BadRequestException(s"User $userIri does not exist.")
- }
+ throw BadRequestException(s"User $userIri does not exist.")
+ }
projects: Seq[ProjectADM] <- userProjectAdminMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield UserProjectAdminMembershipsGetResponseADM(projects = projects)
- }
/**
- * Adds a user to the project admin group of a project.
- *
- * @param userIri the user's IRI.
- * @param projectIri the project's IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return
- */
- private def userProjectAdminMembershipAddRequestADM(userIri: IRI,
- projectIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- // log.debug(s"userProjectAdminMembershipAddRequestV1: userIri: {}, projectIri: {}", userIri, projectIri)
+ * Adds a user to the project admin group of a project.
+ *
+ * @param userIri the user's IRI.
+ * @param projectIri the project's IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return
+ */
+ private def userProjectAdminMembershipAddRequestADM(
+ userIri: IRI,
+ projectIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual task run with an IRI lock.
- */
- def userProjectAdminMembershipAddRequestTask(userIri: IRI,
- projectIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (projectIri.isEmpty) throw BadRequestException("Project IRI cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
- // not a project or system admin
- // log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException(
- "User's project admin membership can only be changed by a project or system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. project admin or system admin)
+ _ <-
+ Future(
+ if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User's project admin membership can only be changed by a project or system administrator"
+ )
+ }
+ )
// check if user exists
userExists <- userExists(userIri)
- _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
+ _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
// check if project exists
projectExists <- projectExists(projectIri)
- _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
+ _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
// get users current project membership list
currentProjectAdminMemberships <- userProjectAdminMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
currentProjectAdminMembershipIris: Seq[IRI] = currentProjectAdminMemberships.map(_.id)
// check if user is already member and if not then append to list
updatedProjectAdminMembershipIris = if (!currentProjectAdminMembershipIris.contains(projectIri)) {
- currentProjectAdminMembershipIris :+ projectIri
- } else {
- throw BadRequestException(s"User $userIri is already a project admin for project $projectIri.")
- }
+ currentProjectAdminMembershipIris :+ projectIri
+ } else {
+ throw BadRequestException(
+ s"User $userIri is already a project admin for project $projectIri."
+ )
+ }
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(projectsAdmin = Some(updatedProjectAdminMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(projectsAdmin = Some(updatedProjectAdminMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userProjectAdminMembershipAddRequestTask(userIri, projectIri, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => userProjectAdminMembershipAddRequestTask(userIri, projectIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * Removes a user from project admin group of a project.
- *
- * @param userIri the user's IRI.
- * @param projectIri the project's IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return
- */
- private def userProjectAdminMembershipRemoveRequestADM(userIri: IRI,
- projectIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- // log.debug(s"userProjectAdminMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri)
+ * Removes a user from project admin group of a project.
+ *
+ * @param userIri the user's IRI.
+ * @param projectIri the project's IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return
+ */
+ private def userProjectAdminMembershipRemoveRequestADM(
+ userIri: IRI,
+ projectIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual task run with an IRI lock.
- */
- def userProjectAdminMembershipRemoveRequestTask(userIri: IRI,
- projectIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (projectIri.isEmpty) throw BadRequestException("Project IRI cannot be empty")
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
- // not a project or system admin
- // log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException(
- "User's project admin membership can only be changed by a project or system administrator")
- }
+ // check if the requesting user is allowed to perform updates (i.e. requesting updates own information or is system admin)
+ _ <-
+ Future(
+ if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
+ throw ForbiddenException(
+ "User's project admin membership can only be changed by a project or system administrator"
+ )
+ }
+ )
// check if user exists
userExists <- userExists(userIri)
- _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
+ _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
// check if project exists
projectExists <- projectExists(projectIri)
- _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
+ _ = if (!projectExists) throw NotFoundException(s"The project $projectIri does not exist.")
// get users current project membership list
currentProjectAdminMemberships <- userProjectAdminMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
currentProjectAdminMembershipIris: Seq[IRI] = currentProjectAdminMemberships.map(_.id)
// check if user is not already a member and if he is then remove the project from to list
updatedProjectAdminMembershipIris = if (currentProjectAdminMembershipIris.contains(projectIri)) {
- currentProjectAdminMembershipIris diff Seq(projectIri)
- } else {
- throw BadRequestException(s"User $userIri is not a project admin of project $projectIri.")
- }
+ currentProjectAdminMembershipIris diff Seq(projectIri)
+ } else {
+ throw BadRequestException(
+ s"User $userIri is not a project admin of project $projectIri."
+ )
+ }
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(projectsAdmin = Some(updatedProjectAdminMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(projectsAdmin = Some(updatedProjectAdminMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
- taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userProjectAdminMembershipRemoveRequestTask(userIri, projectIri, requestingUser, apiRequestID)
- )
+ taskResult <-
+ IriLocker.runWithIriLock(
+ apiRequestID,
+ userIri,
+ () => userProjectAdminMembershipRemoveRequestTask(userIri, projectIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * Returns the user's group memberships as a sequence of [[GroupADM]]
- *
- * @param userIri the IRI of the user.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @return a sequence of [[GroupADM]].
- */
- private def userGroupMembershipsGetADM(userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[Seq[GroupADM]] = {
-
+ * Returns the user's group memberships as a sequence of [[GroupADM]]
+ *
+ * @param userIri the IRI of the user.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @return a sequence of [[GroupADM]].
+ */
+ private def userGroupMembershipsGetADM(
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[Seq[GroupADM]] =
for {
maybeUserADM: Option[UserADM] <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- userInformationType = UserInformationTypeADM.FULL,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ userInformationType = UserInformationTypeADM.FULL,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
groups: Seq[GroupADM] = maybeUserADM match {
- case Some(user) =>
- log.debug("userGroupMembershipsGetADM - user found. Returning his groups: {}.", user.groups)
- user.groups
- case None =>
- log.debug("userGroupMembershipsGetADM - user not found. Returning empty seq.")
- Seq.empty[GroupADM]
- }
+ case Some(user) =>
+ log.debug(
+ "userGroupMembershipsGetADM - user found. Returning his groups: {}.",
+ user.groups
+ )
+ user.groups
+ case None =>
+ log.debug("userGroupMembershipsGetADM - user not found. Returning empty seq.")
+ Seq.empty[GroupADM]
+ }
} yield groups
- }
/**
- * Returns the user's group memberships as a [[UserGroupMembershipsGetResponseADM]]
- *
- * @param userIri the IRI of the user.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @return a [[UserGroupMembershipsGetResponseADM]].
- */
- private def userGroupMembershipsGetRequestADM(userIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM): Future[UserGroupMembershipsGetResponseADM] = {
-
+ * Returns the user's group memberships as a [[UserGroupMembershipsGetResponseADM]]
+ *
+ * @param userIri the IRI of the user.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @return a [[UserGroupMembershipsGetResponseADM]].
+ */
+ private def userGroupMembershipsGetRequestADM(
+ userIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM
+ ): Future[UserGroupMembershipsGetResponseADM] =
for {
groups: Seq[GroupADM] <- userGroupMembershipsGetADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
} yield UserGroupMembershipsGetResponseADM(groups = groups)
- }
-
/**
- * Adds a user to a group.
- *
- * @param userIri the user's IRI.
- * @param groupIri the group IRI.
- * @param featureFactoryConfig the feature factory configuration.
- * @param requestingUser the requesting user.
- * @param apiRequestID the unique api request ID.
- * @return a [[UserOperationResponseADM]].
- */
- private def userGroupMembershipAddRequestADM(userIri: IRI,
- groupIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- log.debug(s"userGroupMembershipAddRequestADM - userIri: {}, groupIri: {}", userIri, groupIri)
+ * Adds a user to a group.
+ *
+ * @param userIri the user's IRI.
+ * @param groupIri the group IRI.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser the requesting user.
+ * @param apiRequestID the unique api request ID.
+ * @return a [[UserOperationResponseADM]].
+ */
+ private def userGroupMembershipAddRequestADM(
+ userIri: IRI,
+ groupIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual task run with an IRI lock.
- */
- def userGroupMembershipAddRequestTask(userIri: IRI,
- groupIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (groupIri.isEmpty) throw BadRequestException("Group IRI cannot be empty")
-
// check if user exists
maybeUser <- getSingleUserADM(
- UserIdentifierADM(maybeIri = Some(userIri)),
- UserInformationTypeADM.FULL,
- featureFactoryConfig = featureFactoryConfig,
- KnoraSystemInstances.Users.SystemUser,
- skipCache = true
- )
+ UserIdentifierADM(maybeIri = Some(userIri)),
+ UserInformationTypeADM.FULL,
+ featureFactoryConfig = featureFactoryConfig,
+ KnoraSystemInstances.Users.SystemUser,
+ skipCache = true
+ )
userToChange: UserADM = maybeUser match {
- case Some(user) => user
- case None => throw NotFoundException(s"The user $userIri does not exist.")
- }
+ case Some(user) => user
+ case None => throw NotFoundException(s"The user $userIri does not exist.")
+ }
// check if group exists
groupExists <- groupExists(groupIri)
- _ = if (!groupExists) throw NotFoundException(s"The group $groupIri does not exist.")
+ _ = if (!groupExists) throw NotFoundException(s"The group $groupIri does not exist.")
// get group's info. we need the project IRI.
maybeGroupADM <- (responderManager ? GroupGetADM(
- groupIri = groupIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[Option[GroupADM]]
+ groupIri = groupIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )).mapTo[Option[GroupADM]]
+
projectIri = maybeGroupADM
- .getOrElse(throw InconsistentRepositoryDataException(s"Group $groupIri does not exist"))
- .project
- .id
+ .getOrElse(throw InconsistentRepositoryDataException(s"Group $groupIri does not exist"))
+ .project
+ .id
- // check if the requesting user is allowed to perform updates
+ // check if the requesting user is allowed to perform updates (i.e. project or system administrator)
_ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin) {
- // not a project or system admin
- // log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException("User's group membership can only be changed by a project or system administrator")
- }
+ throw ForbiddenException(
+ "User's group membership can only be changed by a project or system administrator"
+ )
+ }
// get users current group membership list
currentGroupMemberships = userToChange.groups
currentGroupMembershipIris: Seq[IRI] = currentGroupMemberships.map(_.id)
- _ = log.debug("userGroupMembershipAddRequestADM - currentGroupMembershipIris: {}", currentGroupMembershipIris)
-
// check if user is already member and if not then append to list
updatedGroupMembershipIris = if (!currentGroupMembershipIris.contains(groupIri)) {
- currentGroupMembershipIris :+ groupIri
- } else {
- throw BadRequestException(s"User $userIri is already member of group $groupIri.")
- }
-
- _ = log.debug("userGroupMembershipAddRequestADM - updatedGroupMembershipIris: {}", updatedGroupMembershipIris)
+ currentGroupMembershipIris :+ groupIri
+ } else {
+ throw BadRequestException(s"User $userIri is already member of group $groupIri.")
+ }
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(groups = Some(updatedGroupMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(groups = Some(updatedGroupMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userGroupMembershipAddRequestTask(userIri, groupIri, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => userGroupMembershipAddRequestTask(userIri, groupIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
- private def userGroupMembershipRemoveRequestADM(userIri: IRI,
- groupIri: IRI,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- log.debug(s"userGroupMembershipRemoveRequestADM - userIri: {}, groupIri: {}", userIri, groupIri)
+ private def userGroupMembershipRemoveRequestADM(
+ userIri: IRI,
+ groupIri: IRI,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
/**
- * The actual task run with an IRI lock.
- */
- def userGroupMembershipRemoveRequestTask(userIri: IRI,
- groupIri: IRI,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] =
+ * 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
- _ <- Future(if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty."))
- _ = if (groupIri.isEmpty) throw BadRequestException("Group IRI cannot be empty")
-
// check if user exists
userExists <- userExists(userIri)
- _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
+ _ = if (!userExists) throw NotFoundException(s"The user $userIri does not exist.")
// check if group exists
projectExists <- groupExists(groupIri)
- _ = if (!projectExists) throw NotFoundException(s"The group $groupIri does not exist.")
+ _ = if (!projectExists) throw NotFoundException(s"The group $groupIri does not exist.")
// get group's info. we need the project IRI.
maybeGroupADM <- (responderManager ? GroupGetADM(
- groupIri = groupIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[Option[GroupADM]]
+ groupIri = groupIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )).mapTo[Option[GroupADM]]
projectIri = maybeGroupADM
- .getOrElse(throw exceptions.InconsistentRepositoryDataException(s"Group $groupIri does not exist"))
- .project
- .id
-
- // check if the requesting user is allowed to perform updates
- _ = if (!requestingUser.permissions.isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin && !requestingUser.isSystemUser) {
- // not a project or system admin
- //log.debug("project admin: {}, system admin: {}", userProfileV1.permissionData.isProjectAdmin(projectIri), userProfileV1.permissionData.isSystemAdmin)
- throw ForbiddenException("User's group membership can only be changed by a project or system administrator")
- }
+ .getOrElse(throw InconsistentRepositoryDataException(s"Group $groupIri does not exist"))
+ .project
+ .id
+
+ // check if the requesting user is allowed to perform updates (i.e. is project or system admin)
+ _ =
+ if (
+ !requestingUser.permissions
+ .isProjectAdmin(projectIri) && !requestingUser.permissions.isSystemAdmin && !requestingUser.isSystemUser
+ ) {
+ throw ForbiddenException("User's group membership can only be changed by a project or system administrator")
+ }
// get users current project membership list
currentGroupMemberships <- userGroupMembershipsGetRequestADM(
- userIri = userIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )
+ userIri = userIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )
currentGroupMembershipIris: Seq[IRI] = currentGroupMemberships.groups.map(_.id)
- _ = log.debug("userGroupMembershipRemoveRequestADM - currentGroupMembershipIris: {}",
- currentGroupMembershipIris)
-
// check if user is not already a member and if he is then remove the project from to list
updatedGroupMembershipIris = if (currentGroupMembershipIris.contains(groupIri)) {
- currentGroupMembershipIris diff Seq(groupIri)
- } else {
- throw BadRequestException(s"User $userIri is not member of group $groupIri.")
- }
-
- _ = log.debug("userGroupMembershipRemoveRequestADM - updatedGroupMembershipIris: {}",
- updatedGroupMembershipIris)
+ currentGroupMembershipIris diff Seq(groupIri)
+ } else {
+ throw BadRequestException(s"User $userIri is not member of group $groupIri.")
+ }
// create the update request
- userUpdatePayload = UserUpdatePayloadADM(groups = Some(updatedGroupMembershipIris))
-
result <- updateUserADM(
- userIri = userIri,
- userUpdatePayload = userUpdatePayload,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = apiRequestID
- )
+ userIri = userIri,
+ userUpdatePayload = UserChangeRequestADM(groups = Some(updatedGroupMembershipIris)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = apiRequestID
+ )
} yield result
for {
// run the task with an IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- userIri,
- () => userGroupMembershipRemoveRequestTask(userIri, groupIri, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ userIri,
+ () => userGroupMembershipRemoveRequestTask(userIri, groupIri, requestingUser, apiRequestID)
+ )
} yield taskResult
}
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @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,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
+ * 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 featureFactoryConfig the feature factory configuration.
+ * @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: UserChangeRequestADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
log.debug("updateUserADM - userUpdatePayload: {}", userUpdatePayload)
- /* Remember: some checks on UserUpdatePayloadV1 are implemented in the case class */
-
- if (userIri.contains(KnoraSystemInstances.Users.SystemUser.id) || userIri.contains(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
+ // check if it is a request for a built-in user
+ if (
+ userIri.contains(KnoraSystemInstances.Users.SystemUser.id) || userIri.contains(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
throw BadRequestException("Changes to built-in users are not allowed.")
}
for {
maybeCurrentUser <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- userInformationType = UserInformationTypeADM.FULL,
- skipCache = true
- )
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ userInformationType = UserInformationTypeADM.FULL,
+ skipCache = true
+ )
_ = if (maybeCurrentUser.isEmpty) {
- throw NotFoundException(s"User '$userIri' not found. Aborting update request.")
- }
+ throw NotFoundException(s"User '$userIri' not found. Aborting update request.")
+ }
+
// we are changing the user, so lets get rid of the cached copy
_ = invalidateCachedUserADM(maybeCurrentUser)
/* Update the user */
+ maybeChangedUsername = userUpdatePayload.username match {
+ case Some(username) => Some(username.value)
+ case None => None
+ }
+ maybeChangedEmail = userUpdatePayload.email match {
+ case Some(email) => Some(email.value)
+ case None => None
+ }
+ maybeChangedGivenName = userUpdatePayload.givenName match {
+ case Some(givenName) =>
+ Some(
+ stringFormatter.toSparqlEncodedString(
+ givenName.value,
+ throw BadRequestException(
+ s"The supplied given name: '${givenName.value}' is not valid."
+ )
+ )
+ )
+ case None => None
+ }
+ maybeChangedFamilyName = userUpdatePayload.familyName match {
+ case Some(familyName) =>
+ Some(
+ stringFormatter.toSparqlEncodedString(
+ familyName.value,
+ throw BadRequestException(
+ s"The supplied family name: '${familyName.value}' is not valid."
+ )
+ )
+ )
+ case None => None
+ }
+ maybeChangedStatus = userUpdatePayload.status match {
+ case Some(status) => Some(status.value)
+ case None => None
+ }
+ maybeChangedLang = userUpdatePayload.lang match {
+ case Some(lang) => Some(lang.value)
+ case None => None
+ }
+ maybeChangedProjects = userUpdatePayload.projects match {
+ case Some(projects) => Some(projects)
+ case None => None
+ }
+ maybeChangedProjectsAdmin = userUpdatePayload.projectsAdmin match {
+ case Some(projectsAdmin) => Some(projectsAdmin)
+ case None => None
+ }
+ maybeChangedGroups = userUpdatePayload.groups match {
+ case Some(groups) => Some(groups)
+ case None => None
+ }
+ maybeChangedSystemAdmin = userUpdatePayload.systemAdmin match {
+ case Some(systemAdmin) => Some(systemAdmin.value)
+ case None => None
+ }
updateUserSparqlString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .updateUser(
- adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph,
- triplestore = settings.triplestoreType,
- userIri = userIri,
- maybeUsername = userUpdatePayload.username,
- maybeEmail = userUpdatePayload.email,
- maybeGivenName = userUpdatePayload.givenName,
- maybeFamilyName = userUpdatePayload.familyName,
- maybePassword = userUpdatePayload.password,
- maybeStatus = userUpdatePayload.status,
- maybeLang = userUpdatePayload.lang,
- maybeProjects = userUpdatePayload.projects,
- maybeProjectsAdmin = userUpdatePayload.projectsAdmin,
- maybeGroups = userUpdatePayload.groups,
- maybeSystemAdmin = userUpdatePayload.systemAdmin
- )
- .toString)
- // _ = log.debug(s"updateUserV1 - query: $updateUserSparqlString")
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .updateUser(
+ adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph,
+ triplestore = settings.triplestoreType,
+ userIri = userIri,
+ maybeUsername = maybeChangedUsername,
+ maybeEmail = maybeChangedEmail,
+ maybeGivenName = maybeChangedGivenName,
+ maybeFamilyName = maybeChangedFamilyName,
+ maybeStatus = maybeChangedStatus,
+ maybeLang = maybeChangedLang,
+ maybeProjects = maybeChangedProjects,
+ maybeProjectsAdmin = maybeChangedProjectsAdmin,
+ maybeGroups = maybeChangedGroups,
+ maybeSystemAdmin = maybeChangedSystemAdmin
+ )
+ .toString
+ )
+
updateResult <- (storeManager ? SparqlUpdateRequest(updateUserSparqlString)).mapTo[SparqlUpdateResponse]
/* Verify that the user was updated. */
maybeUpdatedUserADM <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- userInformationType = UserInformationTypeADM.FULL,
- skipCache = true
- )
-
- updatedUserADM: UserADM = maybeUpdatedUserADM.getOrElse(
- throw UpdateNotPerformedException("User was not updated. Please report this as a possible bug."))
-
- // _ = log.debug(s"===>>> apiUpdateRequest: $userUpdatePayload / updatedUserADM: $updatedUserADM")
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ userInformationType = UserInformationTypeADM.FULL,
+ skipCache = true
+ )
+
+ updatedUserADM: UserADM =
+ maybeUpdatedUserADM.getOrElse(
+ throw UpdateNotPerformedException("User was not updated. Please report this as a possible bug.")
+ )
_ = if (userUpdatePayload.username.isDefined) {
- if (updatedUserADM.username != userUpdatePayload.username.get)
- throw UpdateNotPerformedException("User's 'username' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.username != userUpdatePayload.username.get.value)
+ throw UpdateNotPerformedException(
+ "User's 'username' was not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.email.isDefined) {
- if (updatedUserADM.email != userUpdatePayload.email.get)
- throw UpdateNotPerformedException("User's 'email' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.email != userUpdatePayload.email.get.value)
+ throw UpdateNotPerformedException("User's 'email' was not updated. Please report this as a possible bug.")
+ }
_ = if (userUpdatePayload.givenName.isDefined) {
- if (updatedUserADM.givenName != userUpdatePayload.givenName.get)
- throw UpdateNotPerformedException("User's 'givenName' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.givenName != userUpdatePayload.givenName.get.value)
+ throw UpdateNotPerformedException(
+ "User's 'givenName' was not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.familyName.isDefined) {
- if (updatedUserADM.familyName != userUpdatePayload.familyName.get)
- throw UpdateNotPerformedException(
- "User's 'familyName' was not updated. Please report this as a possible bug.")
- }
-
- _ = if (userUpdatePayload.password.isDefined) {
- if (updatedUserADM.password != userUpdatePayload.password)
- throw UpdateNotPerformedException("User's 'password' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.familyName != userUpdatePayload.familyName.get.value)
+ throw UpdateNotPerformedException(
+ "User's 'familyName' was not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.status.isDefined) {
- if (updatedUserADM.status != userUpdatePayload.status.get)
- throw UpdateNotPerformedException("User's 'status' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.status != userUpdatePayload.status.get.value)
+ throw UpdateNotPerformedException(
+ "User's 'status' was not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.lang.isDefined) {
- if (updatedUserADM.lang != userUpdatePayload.lang.get)
- throw UpdateNotPerformedException("User's 'lang' was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.lang != userUpdatePayload.lang.get.value)
+ throw UpdateNotPerformedException("User's 'lang' was not updated. Please report this as a possible bug.")
+ }
+
+ _ = if (userUpdatePayload.projects.isDefined) {
+ if (updatedUserADM.projects.map(_.id) != userUpdatePayload.projects.get)
+ throw UpdateNotPerformedException(
+ "User's 'project' memberships where not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.systemAdmin.isDefined) {
- if (updatedUserADM.permissions.isSystemAdmin != userUpdatePayload.systemAdmin.get)
- throw UpdateNotPerformedException(
- "User's 'isInSystemAdminGroup' status was not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.permissions.isSystemAdmin != userUpdatePayload.systemAdmin.get.value)
+ throw UpdateNotPerformedException(
+ "User's 'isInSystemAdminGroup' status was not updated. Please report this as a possible bug."
+ )
+ }
_ = if (userUpdatePayload.groups.isDefined) {
- if (updatedUserADM.groups.map(_.id) != userUpdatePayload.groups.get)
- throw UpdateNotPerformedException(
- "User's 'group' memberships where not updated. Please report this as a possible bug.")
- }
+ if (updatedUserADM.groups.map(_.id) != userUpdatePayload.groups.get)
+ throw UpdateNotPerformedException(
+ "User's 'group' memberships where not updated. Please report this as a possible bug."
+ )
+ }
+
+ } yield UserOperationResponseADM(updatedUserADM.ofType(UserInformationTypeADM.RESTRICTED))
+ }
+
+ /**
+ * Updates the password for a user.
+ *
+ * @param userIri the IRI of the existing user that we want to update.
+ * @param password the new password.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @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 updateUserPasswordADM(
+ userIri: IRI,
+ password: Password,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
+
+ // check if it is a request for a built-in user
+ if (
+ userIri.contains(KnoraSystemInstances.Users.SystemUser.id) || userIri.contains(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
+ for {
+ maybeCurrentUser <- getSingleUserADM(
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ userInformationType = UserInformationTypeADM.FULL,
+ skipCache = true
+ )
+
+ _ = if (maybeCurrentUser.isEmpty) {
+ throw NotFoundException(s"User '$userIri' not found. Aborting update request.")
+ }
+ // we are changing the user, so lets get rid of the cached copy
+ _ = invalidateCachedUserADM(maybeCurrentUser)
+
+ // update the password
+ updateUserSparqlString <- Future(
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .updateUserPassword(
+ adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph,
+ triplestore = settings.triplestoreType,
+ userIri = userIri,
+ newPassword = password.value
+ )
+ .toString
+ )
+
+ updateResult <- (storeManager ? SparqlUpdateRequest(updateUserSparqlString)).mapTo[SparqlUpdateResponse]
+
+ /* Verify that the password was updated. */
+ maybeUpdatedUserADM <- getSingleUserADM(
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ userInformationType = UserInformationTypeADM.FULL,
+ skipCache = true
+ )
+
+ updatedUserADM: UserADM =
+ maybeUpdatedUserADM.getOrElse(
+ throw UpdateNotPerformedException("User was not updated. Please report this as a possible bug.")
+ )
+
+ _ = if (updatedUserADM.password.get != password.value)
+ throw UpdateNotPerformedException("User's password was not updated. Please report this as a possible bug.")
} yield UserOperationResponseADM(updatedUserADM.ofType(UserInformationTypeADM.RESTRICTED))
}
/**
- * 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 featureFactoryConfig the feature factory configuration.
- * @param requestingUser a [[UserADM]] object containing information about the requesting user.
- * @return a future containing the [[UserOperationResponseADM]].
- */
- private def createNewUserADM(createRequest: CreateUserApiRequestADM,
- featureFactoryConfig: FeatureFactoryConfig,
- requestingUser: UserADM,
- apiRequestID: UUID): Future[UserOperationResponseADM] = {
-
- log.debug("createNewUserADM - createRequest: {}", createRequest)
+ * 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 userCreatePayloadADM a [[UserCreatePayloadADM]] object containing information about the new user to be created.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @param requestingUser a [[UserADM]] object containing information about the requesting user.
+ * @return a future containing the [[UserOperationResponseADM]].
+ */
+ private def createNewUserADM(
+ userCreatePayloadADM: UserCreatePayloadADM,
+ featureFactoryConfig: FeatureFactoryConfig,
+ requestingUser: UserADM,
+ apiRequestID: UUID
+ ): Future[UserOperationResponseADM] = {
+
+ log.debug("createNewUserADM - userCreatePayloadADM: {}", userCreatePayloadADM)
/**
- * The actual task run with an IRI lock.
- */
- def createNewUserTask(createRequest: CreateUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID) =
+ * The actual task run with an IRI lock.
+ */
+ def createNewUserTask(userCreatePayloadADM: UserCreatePayloadADM) =
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"))
-
- // 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"))
-
- // check other
- _ = if (createRequest.password.isEmpty) throw BadRequestException("Password cannot be empty")
- _ = 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(Some(createRequest.username))
+ // check if username is unique
+ usernameTaken: Boolean <- userByUsernameExists(userCreatePayloadADM.username)
_ = if (usernameTaken) {
- throw DuplicateValueException(s"User with the username '${createRequest.username}' already exists")
- }
+ throw DuplicateValueException(
+ s"User with the username '${userCreatePayloadADM.username.get.value}' already exists"
+ )
+ }
- emailTaken: Boolean <- userByEmailExists(Some(createRequest.email))
+ // check if email is unique
+ emailTaken: Boolean <- userByEmailExists(userCreatePayloadADM.email)
_ = if (emailTaken) {
- throw DuplicateValueException(s"User with the email '${createRequest.email}' already exists")
- }
+ throw DuplicateValueException(
+ s"User with the email '${userCreatePayloadADM.email.get.value}' already exists"
+ )
+ }
// check the custom IRI; if not given, create an unused IRI
- customUserIri: Option[SmartIri] = createRequest.id.map(iri => iri.toSmartIri)
- userIri: IRI <- checkOrCreateEntityIri(customUserIri, stringFormatter.makeRandomPersonIri)
+ customUserIri: Option[SmartIri] = userCreatePayloadADM.id.map(iri => iri.toSmartIri)
+ userIri: IRI <- checkOrCreateEntityIri(customUserIri, stringFormatter.makeRandomPersonIri)
- encoder = new BCryptPasswordEncoder(settings.bcryptPasswordStrength)
- hashedPassword = encoder.encode(createRequest.password)
+ // hash password
+ encoder = new BCryptPasswordEncoder(settings.bcryptPasswordStrength)
+ hashedPassword = encoder.encode(userCreatePayloadADM.password.get.value)
// Create the new user.
createNewUserSparqlString = org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .createNewUser(
- adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph,
- triplestore = settings.triplestoreType,
- userIri = userIri,
- userClassIri = OntologyConstants.KnoraAdmin.User,
- username = stringFormatter.validateAndEscapeUsername(
- createRequest.username,
- throw BadRequestException(s"The username '${createRequest.username}' contains invalid characters")),
- email = createRequest.email,
- password = hashedPassword,
- givenName = createRequest.givenName,
- familyName = createRequest.familyName,
- status = createRequest.status,
- preferredLanguage = createRequest.lang,
- systemAdmin = createRequest.systemAdmin
- )
- .toString
- // _ = log.debug(s"createNewUser: $createNewUserSparqlString")
+ .createNewUser(
+ adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph,
+ triplestore = settings.triplestoreType,
+ userIri = userIri,
+ userClassIri = OntologyConstants.KnoraAdmin.User,
+ username = stringFormatter.toSparqlEncodedString(
+ userCreatePayloadADM.username.get.value,
+ errorFun = throw BadRequestException(
+ s"The supplied username: '${userCreatePayloadADM.username.get.value}' is not valid."
+ )
+ ),
+ email = stringFormatter.toSparqlEncodedString(
+ userCreatePayloadADM.email.get.value,
+ errorFun = throw BadRequestException(
+ s"The supplied email: '${userCreatePayloadADM.email.get.value}' is not valid."
+ )
+ ),
+ password = hashedPassword,
+ givenName = stringFormatter.toSparqlEncodedString(
+ userCreatePayloadADM.givenName.get.value,
+ errorFun = throw BadRequestException(
+ s"The supplied given name: '${userCreatePayloadADM.givenName.get.value}' is not valid."
+ )
+ ),
+ familyName = stringFormatter.toSparqlEncodedString(
+ userCreatePayloadADM.familyName.get.value,
+ errorFun = throw BadRequestException(
+ s"The supplied family name: '${userCreatePayloadADM.familyName.get.value}' is not valid."
+ )
+ ),
+ status = userCreatePayloadADM.status.get.value,
+ preferredLanguage = stringFormatter.toSparqlEncodedString(
+ userCreatePayloadADM.lang.get.value,
+ errorFun = throw BadRequestException(
+ s"The supplied language: '${userCreatePayloadADM.lang.get.value}' is not valid."
+ )
+ ),
+ systemAdmin = userCreatePayloadADM.systemAdmin.get.value
+ )
+ .toString
+
+ _ = log.debug(s"createNewUser: $createNewUserSparqlString")
+
createNewUserResponse <- (storeManager ? SparqlUpdateRequest(createNewUserSparqlString))
- .mapTo[SparqlUpdateResponse]
+ .mapTo[SparqlUpdateResponse]
// try to retrieve newly created user (will also add to cache)
maybeNewUserADM: Option[UserADM] <- getSingleUserADM(
- identifier = UserIdentifierADM(maybeIri = Some(userIri)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser,
- userInformationType = UserInformationTypeADM.FULL,
- skipCache = true
- )
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser,
+ userInformationType = UserInformationTypeADM.FULL,
+ skipCache = true
+ )
// check to see if we could retrieve the new user
- newUserADM = maybeNewUserADM.getOrElse(
- throw UpdateNotPerformedException(s"User $userIri was not created. Please report this as a possible bug.")
- )
+ newUserADM =
+ maybeNewUserADM.getOrElse(
+ throw UpdateNotPerformedException(s"User $userIri was not created. Please report this as a possible bug.")
+ )
// create the user operation response
- _ = log.debug("createNewUserADM - created new user: {}", newUserADM)
+ _ = log.debug("createNewUserADM - created new user: {}", newUserADM)
userOperationResponseADM = UserOperationResponseADM(newUserADM.ofType(UserInformationTypeADM.RESTRICTED))
} yield userOperationResponseADM
-
for {
// run user creation with an global IRI lock
taskResult <- IriLocker.runWithIriLock(
- apiRequestID,
- USERS_GLOBAL_LOCK_IRI,
- () => createNewUserTask(createRequest, requestingUser, apiRequestID)
- )
+ apiRequestID,
+ USERS_GLOBAL_LOCK_IRI,
+ () => createNewUserTask(userCreatePayloadADM)
+ )
} yield taskResult
}
@@ -1621,87 +1798,92 @@ 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.
- */
- private def getUserFromCacheOrTriplestore(identifier: UserIdentifierADM,
- featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] = {
+ * 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,
+ featureFactoryConfig: FeatureFactoryConfig
+ ): Future[Option[UserADM]] =
if (cacheServiceSettings.cacheServiceEnabled) {
// caching enabled
- getUserFromCache(identifier)
- .flatMap {
- case None =>
- // none found in cache. getting from triplestore.
- getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig)
- .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))
- }
+ getUserFromCache(identifier).flatMap {
+ case None =>
+ // none found in cache. getting from triplestore.
+ getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig).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.")
getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig)
}
- }
/**
- * Tries to retrieve a [[UserADM]] from the triplestore.
- */
- private def getUserFromTriplestore(identifier: UserIdentifierADM,
- featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] =
+ * Tries to retrieve a [[UserADM]] from the triplestore.
+ */
+ private def getUserFromTriplestore(
+ identifier: UserIdentifierADM,
+ featureFactoryConfig: FeatureFactoryConfig
+ ): Future[Option[UserADM]] =
for {
sparqlQueryString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .getUsers(
- triplestore = settings.triplestoreType,
- maybeIri = identifier.toIriOption,
- maybeUsername = identifier.toUsernameOption,
- maybeEmail = identifier.toEmailOption
- )
- .toString())
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .getUsers(
+ triplestore = settings.triplestoreType,
+ maybeIri = identifier.toIriOption,
+ maybeUsername = identifier.toUsernameOption,
+ maybeEmail = identifier.toEmailOption
+ )
+ .toString()
+ )
userQueryResponse <- (storeManager ? SparqlExtendedConstructRequest(
- sparql = sparqlQueryString,
- featureFactoryConfig = featureFactoryConfig
- )).mapTo[SparqlExtendedConstructResponse]
+ sparql = sparqlQueryString,
+ featureFactoryConfig = featureFactoryConfig
+ )).mapTo[SparqlExtendedConstructResponse]
maybeUserADM: Option[UserADM] <- if (userQueryResponse.statements.nonEmpty) {
- log.debug("getUserFromTriplestore - triplestore hit for: {}", identifier)
- statements2UserADM(
- statements = userQueryResponse.statements.head,
- featureFactoryConfig = featureFactoryConfig
- )
- } else {
- log.debug("getUserFromTriplestore - no triplestore hit for: {}", identifier)
- FastFuture.successful(None)
- }
+ log.debug("getUserFromTriplestore - triplestore hit for: {}", identifier)
+ statements2UserADM(
+ statements = userQueryResponse.statements.head,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } else {
+ log.debug("getUserFromTriplestore - no triplestore hit for: {}", identifier)
+ FastFuture.successful(None)
+ }
} yield maybeUserADM
/**
- * Helper method used to create a [[UserADM]] from the [[SparqlExtendedConstructResponse]] containing user data.
- *
- * @param statements result from the SPARQL query containing user data.
- * @param featureFactoryConfig the feature factory configuration.
- * @return a [[UserADM]] containing the user's data.
- */
- private def statements2UserADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]]),
- featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] = {
+ * Helper method used to create a [[UserADM]] from the [[SparqlExtendedConstructResponse]] containing user data.
+ *
+ * @param statements result from the SPARQL query containing user data.
+ * @param featureFactoryConfig the feature factory configuration.
+ * @return a [[UserADM]] containing the user's data.
+ */
+ private def statements2UserADM(
+ statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]]),
+ featureFactoryConfig: FeatureFactoryConfig
+ ): Future[Option[UserADM]] = {
// log.debug("statements2UserADM - statements: {}", statements)
- val userIri: IRI = statements._1.toString
+ val userIri: IRI = statements._1.toString
val propsMap: Map[SmartIri, Seq[LiteralV2]] = statements._2
// log.debug("statements2UserADM - userIri: {}", userIri)
@@ -1737,88 +1919,99 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
for {
/* get the user's permission profile from the permissions responder */
permissionData <- (responderManager ? PermissionDataGetADM(
- projectIris = projectIris,
- groupIris = groupIris,
- isInProjectAdminGroups = isInProjectAdminGroups,
- isInSystemAdminGroup = isInSystemAdminGroup,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[PermissionsDataADM]
+ projectIris = projectIris,
+ groupIris = groupIris,
+ isInProjectAdminGroups = isInProjectAdminGroups,
+ isInSystemAdminGroup = isInSystemAdminGroup,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )).mapTo[PermissionsDataADM]
maybeGroupFutures: Seq[Future[Option[GroupADM]]] = groupIris.map { groupIri =>
- (responderManager ? GroupGetADM(
- groupIri = groupIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[Option[GroupADM]]
- }
+ (responderManager ? GroupGetADM(
+ groupIri = groupIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = KnoraSystemInstances.Users.SystemUser
+ )).mapTo[Option[GroupADM]]
+ }
maybeGroups: Seq[Option[GroupADM]] <- Future.sequence(maybeGroupFutures)
- groups: Seq[GroupADM] = maybeGroups.flatten
+ groups: Seq[GroupADM] = maybeGroups.flatten
// _ = log.debug("statements2UserADM - groups: {}", MessageUtil.toSource(groups))
maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { projectIri =>
- (responderManager ? ProjectGetADM(
- ProjectIdentifierADM(maybeIri = Some(projectIri)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = KnoraSystemInstances.Users.SystemUser
- )).mapTo[Option[ProjectADM]]
- }
+ (responderManager ? ProjectGetADM(
+ ProjectIdentifierADM(maybeIri = Some(projectIri)),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser =
+ KnoraSystemInstances.Users.SystemUser
+ )).mapTo[Option[ProjectADM]]
+ }
maybeProjects: Seq[Option[ProjectADM]] <- Future.sequence(maybeProjectFutures)
- projects: Seq[ProjectADM] = maybeProjects.flatten
+ projects: Seq[ProjectADM] = maybeProjects.flatten
// _ = log.debug("statements2UserADM - projects: {}", MessageUtil.toSource(projects))
/* construct the user profile from the different parts */
user = UserADM(
- id = userIri,
- username = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Username.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'username' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- email = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Email.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'email' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- password = propsMap
- .get(OntologyConstants.KnoraAdmin.Password.toSmartIri)
- .map(_.head.asInstanceOf[StringLiteralV2].value),
- token = None,
- givenName = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.GivenName.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'givenName' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- familyName = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.FamilyName.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'familyName' defined."))
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- status = propsMap
- .getOrElse(OntologyConstants.KnoraAdmin.Status.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'status' defined."))
- .head
- .asInstanceOf[BooleanLiteralV2]
- .value,
- lang = propsMap
- .getOrElse(
- OntologyConstants.KnoraAdmin.PreferredLanguage.toSmartIri,
- throw InconsistentRepositoryDataException(s"User: $userIri has no 'preferredLanguage' defined.")
- )
- .head
- .asInstanceOf[StringLiteralV2]
- .value,
- groups = groups,
- projects = projects,
- sessionId = None,
- permissions = permissionData
- )
+ id = userIri,
+ username = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Username.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'username' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ email = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Email.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'email' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ password = propsMap
+ .get(OntologyConstants.KnoraAdmin.Password.toSmartIri)
+ .map(_.head.asInstanceOf[StringLiteralV2].value),
+ token = None,
+ givenName = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.GivenName.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'givenName' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ familyName = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.FamilyName.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'familyName' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ status = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.Status.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'status' defined.")
+ )
+ .head
+ .asInstanceOf[BooleanLiteralV2]
+ .value,
+ lang = propsMap
+ .getOrElse(
+ OntologyConstants.KnoraAdmin.PreferredLanguage.toSmartIri,
+ throw InconsistentRepositoryDataException(s"User: $userIri has no 'preferredLanguage' defined.")
+ )
+ .head
+ .asInstanceOf[StringLiteralV2]
+ .value,
+ groups = groups,
+ projects = projects,
+ sessionId = None,
+ permissions = permissionData
+ )
// _ = log.debug(s"statements2UserADM - user: {}", user.toString)
result: Option[UserADM] = Some(user)
@@ -1830,46 +2023,49 @@ 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]].
- */
- private def userExists(userIri: IRI): Future[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(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkUserExists(userIri = userIri).toString)
+ askString <-
+ Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkUserExists(userIri = userIri).toString)
// _ = log.debug("userExists - query: {}", askString)
checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse]
- result = checkUserExistsResponse.result
+ result = checkUserExistsResponse.result
} yield 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] = {
+ * 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[Username],
+ maybeCurrent: Option[String] = None
+ ): Future[Boolean] =
maybeUsername match {
case Some(username) =>
- if (maybeCurrent.contains(username)) {
+ if (maybeCurrent.contains(username.value)) {
FastFuture.successful(true)
} else {
stringFormatter.validateUsername(
- username,
- throw BadRequestException(s"The username '$username' contains invalid characters"))
+ username.value,
+ throw BadRequestException(s"The username '${username.value}' contains invalid characters")
+ )
for {
askString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .checkUserExistsByUsername(username = username)
- .toString)
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .checkUserExistsByUsername(username = username.value)
+ .toString
+ )
// _ = log.debug("userExists - query: {}", askString)
checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse]
@@ -1878,27 +2074,31 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
case None => FastFuture.successful(false)
}
- }
/**
- * 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] = {
+ * 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[Email], maybeCurrent: Option[String] = None): Future[Boolean] =
maybeEmail match {
case Some(email) =>
- if (maybeCurrent.contains(email)) {
+ if (maybeCurrent.contains(email.value)) {
FastFuture.successful(true)
} else {
- stringFormatter.validateEmailAndThrow(email,
- throw BadRequestException(s"The email address '$email' is invalid"))
+ stringFormatter.validateEmailAndThrow(
+ email.value,
+ throw BadRequestException(s"The email address '${email.value}' is invalid")
+ )
for {
askString <- Future(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkUserExistsByEmail(email = email).toString)
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .checkUserExistsByEmail(email = email.value)
+ .toString
+ )
// _ = log.debug("userExists - query: {}", askString)
checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse]
@@ -1907,49 +2107,49 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
case None => FastFuture.successful(false)
}
- }
/**
- * 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] = {
+ * 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(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt
- .checkProjectExistsByIri(projectIri = projectIri)
- .toString)
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt
+ .checkProjectExistsByIri(projectIri = projectIri)
+ .toString
+ )
// _ = log.debug("projectExists - query: {}", askString)
checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse]
- result = checkUserExistsResponse.result
+ result = checkUserExistsResponse.result
} yield result
- }
/**
- * 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] = {
+ * 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(
- org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkGroupExistsByIri(groupIri = groupIri).toString)
+ askString <-
+ Future(
+ org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkGroupExistsByIri(groupIri = groupIri).toString
+ )
// _ = log.debug("groupExists - query: {}", askString)
checkUserExistsResponse <- (storeManager ? SparqlAskRequest(askString)).mapTo[SparqlAskResponse]
- result = checkUserExistsResponse.result
+ result = checkUserExistsResponse.result
} yield result
- }
/**
- * 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 {
@@ -1963,12 +2163,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 =>
@@ -1978,9 +2178,9 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
}
/**
- * Removes the user from cache.
- */
- private def invalidateCachedUserADM(maybeUser: Option[UserADM]): Future[Boolean] = {
+ * Removes the user from cache.
+ */
+ private def invalidateCachedUserADM(maybeUser: Option[UserADM]): Future[Boolean] =
if (cacheServiceSettings.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
@@ -1999,6 +2199,4 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde
FastFuture.successful(true)
}
- }
-
}
diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala
index 1a13908d3d..614de266b4 100644
--- a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala
+++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala
@@ -19,20 +19,19 @@
package org.knora.webapi.routing.admin
-import java.util.UUID
-
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{PathMatcher, Route}
import io.swagger.annotations._
-import javax.ws.rs.Path
import org.knora.webapi.annotation.ApiMayChange
-import org.knora.webapi.exceptions.BadRequestException
+import org.knora.webapi.exceptions.{BadRequestException}
import org.knora.webapi.feature.FeatureFactoryConfig
import org.knora.webapi.messages.admin.responder.usersmessages.UsersADMJsonProtocol._
-import org.knora.webapi.messages.admin.responder.usersmessages._
+import org.knora.webapi.messages.admin.responder.usersmessages.{UserUpdatePasswordPayloadADM, _}
import org.knora.webapi.messages.util.KnoraSystemInstances
import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilADM}
+import java.util.UUID
+import javax.ws.rs.Path
import scala.concurrent.Future
object UsersRouteADM {
@@ -40,8 +39,8 @@ object UsersRouteADM {
}
/**
- * Provides an akka-http-routing function for API routes that deal with users.
- */
+ * Provides an akka-http-routing function for API routes that deal with users.
+ */
@Api(value = "users", produces = "application/json")
@Path("/admin/users")
class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) with Authenticator {
@@ -49,8 +48,8 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
import UsersRouteADM._
/**
- * Returns the route.
- */
+ * Returns the route.
+ */
override def makeRoute(featureFactoryConfig: FeatureFactoryConfig): Route =
getUsers(featureFactoryConfig) ~
addUser(featureFactoryConfig) ~
@@ -61,7 +60,7 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
changeUserPassword(featureFactoryConfig) ~
changeUserStatus(featureFactoryConfig) ~
deleteUser(featureFactoryConfig) ~
- changeUserSytemAdminMembership(featureFactoryConfig) ~
+ changeUserSystemAdminMembership(featureFactoryConfig) ~
getUsersProjectMemberships(featureFactoryConfig) ~
addUserToProjectMembership(featureFactoryConfig) ~
removeUserFromProjectMembership(featureFactoryConfig) ~
@@ -75,20 +74,20 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
@ApiResponses(
Array(
new ApiResponse(code = 500, message = "Internal server error")
- ))
+ )
+ )
/* return all users */
def getUsers(featureFactoryConfig: FeatureFactoryConfig): Route = path(UsersBasePath) {
get { requestContext =>
val requestMessage: Future[UsersGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UsersGetRequestADM(
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UsersGetRequestADM(
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -101,38 +100,56 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
}
- @ApiOperation(value = "Add new user",
- nickname = "addUser",
- httpMethod = "POST",
- response = classOf[UserOperationResponseADM])
+ @ApiOperation(
+ value = "Add new user",
+ nickname = "addUser",
+ httpMethod = "POST",
+ response = classOf[UserOperationResponseADM]
+ )
@ApiImplicitParams(
Array(
- new ApiImplicitParam(name = "body",
- value = "\"user\" to create",
- required = true,
- dataTypeClass = classOf[CreateUserApiRequestADM],
- paramType = "body")
- ))
+ new ApiImplicitParam(
+ name = "body",
+ value = "\"user\" to create",
+ required = true,
+ dataTypeClass = classOf[CreateUserApiRequestADM],
+ paramType = "body"
+ )
+ )
+ )
@ApiResponses(
Array(
new ApiResponse(code = 500, message = "Internal server error")
- ))
+ )
+ )
/* create a new user */
def addUser(featureFactoryConfig: FeatureFactoryConfig): Route = path(UsersBasePath) {
post {
entity(as[CreateUserApiRequestADM]) { apiRequest => requestContext =>
+ // get all values from request and make value objects from it
+ val user: UserCreatePayloadADM =
+ UserCreatePayloadADM.create(
+ id = stringFormatter.validateOptionalUserIri(apiRequest.id, throw BadRequestException(s"Invalid user IRI")),
+ username = Username.create(apiRequest.username).fold(error => throw error, value => value),
+ email = Email.create(apiRequest.email).fold(error => throw error, value => value),
+ givenName = GivenName.create(apiRequest.givenName).fold(error => throw error, value => value),
+ familyName = FamilyName.create(apiRequest.familyName).fold(error => throw error, value => value),
+ password = Password.create(apiRequest.password).fold(error => throw error, value => value),
+ status = Status.create(apiRequest.status).fold(error => throw error, value => value),
+ lang = LanguageCode.create(apiRequest.lang).fold(error => throw error, value => value),
+ systemAdmin = SystemAdmin.create(apiRequest.systemAdmin).fold(error => throw error, value => value)
+ )
val requestMessage: Future[UserCreateRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserCreateRequestADM(
- createRequest = apiRequest,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserCreateRequestADM(
+ userCreatePayloadADM = user,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -147,23 +164,22 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * return a single user identified by iri
- */
+ * return a single user identified by iri
+ */
private def getUserByIri(featureFactoryConfig: FeatureFactoryConfig): Route = path(UsersBasePath / "iri" / Segment) {
- value =>
+ userIri =>
get { requestContext =>
val requestMessage: Future[UserGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGetRequestADM(
- identifier = UserIdentifierADM(maybeIri = Some(value)),
- userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGetRequestADM(
+ identifier = UserIdentifierADM(maybeIri = Some(userIri)),
+ userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -177,23 +193,22 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * return a single user identified by email
- */
+ * return a single user identified by email
+ */
private def getUserByEmail(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "email" / Segment) { value =>
+ path(UsersBasePath / "email" / Segment) { userIri =>
get { requestContext =>
val requestMessage: Future[UserGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGetRequestADM(
- identifier = UserIdentifierADM(maybeEmail = Some(value)),
- userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGetRequestADM(
+ identifier = UserIdentifierADM(maybeEmail = Some(userIri)),
+ userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -207,23 +222,22 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * return a single user identified by username
- */
+ * return a single user identified by username
+ */
private def getUserByUsername(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "username" / Segment) { value =>
+ path(UsersBasePath / "username" / Segment) { userIri =>
get { requestContext =>
val requestMessage: Future[UserGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGetRequestADM(
- identifier = UserIdentifierADM(maybeUsername = Some(value)),
- userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGetRequestADM(
+ identifier = UserIdentifierADM(maybeUsername = Some(userIri)),
+ userInformationTypeADM = UserInformationTypeADM.RESTRICTED,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -237,36 +251,69 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: Change existing user's basic information.
- */
+ * API MAY CHANGE: Change existing user's basic information.
+ */
@ApiMayChange
private def changeUserBasicInformation(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "iri" / Segment / "BasicUserInformation") { value =>
+ path(UsersBasePath / "iri" / Segment / "BasicUserInformation") { userIri =>
put {
entity(as[ChangeUserApiRequestADM]) { apiRequest => requestContext =>
- val userIri =
- stringFormatter.validateAndEscapeUserIri(value, throw BadRequestException(s"Invalid user IRI $value"))
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- if (userIri.equals(KnoraSystemInstances.Users.SystemUser.id) || userIri.equals(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
throw BadRequestException("Changes to built-in users are not allowed.")
}
- /* the api request is already checked at time of creation. see case class. */
+ val maybeChangedUsername = apiRequest.username match {
+ case Some(username) => Some(Username.create(username).fold(error => throw error, value => value))
+ case None => None
+ }
+ val maybeChangedEmail = apiRequest.email match {
+ case Some(email) => Some(Email.create(email).fold(error => throw error, value => value))
+ case None => None
+ }
+ val maybeChangedGivenName = apiRequest.givenName match {
+ case Some(givenName) => Some(GivenName.create(givenName).fold(error => throw error, value => value))
+ case None => None
+ }
+ val maybeChangedFamilyName = apiRequest.familyName match {
+ case Some(familyName) => Some(FamilyName.create(familyName).fold(error => throw error, value => value))
+ case None => None
+ }
+ val maybeChangedLang = apiRequest.lang match {
+ case Some(lang) => Some(LanguageCode.create(lang).fold(error => throw error, value => value))
+ case None => None
+ }
+
+ val userUpdatePayload: UserUpdateBasicInformationPayloadADM =
+ UserUpdateBasicInformationPayloadADM(
+ username = maybeChangedUsername,
+ email = maybeChangedEmail,
+ givenName = maybeChangedGivenName,
+ familyName = maybeChangedFamilyName,
+ lang = maybeChangedLang
+ )
+ /* the api request is already checked at time of creation. see case class. */
val requestMessage: Future[UsersResponderRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserChangeBasicUserInformationRequestADM(
- userIri = userIri,
- changeUserRequest = apiRequest,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserChangeBasicInformationRequestADM(
+ userIri = checkedUserIri,
+ userUpdateBasicInformationPayload = userUpdatePayload,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -281,36 +328,47 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: Change user's password.
- */
+ * API MAY CHANGE: Change user's password.
+ */
@ApiMayChange
private def changeUserPassword(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "iri" / Segment / "Password") { value =>
+ path(UsersBasePath / "iri" / Segment / "Password") { userIri =>
put {
- entity(as[ChangeUserApiRequestADM]) { apiRequest => requestContext =>
- val userIri =
- stringFormatter.validateAndEscapeUserIri(value, throw BadRequestException(s"Invalid user IRI $value"))
+ entity(as[ChangeUserPasswordApiRequestADM]) { apiRequest => requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- if (userIri.equals(KnoraSystemInstances.Users.SystemUser.id) || userIri.equals(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
throw BadRequestException("Changes to built-in users are not allowed.")
}
- /* the api request is already checked at time of creation. see case class. */
+ val requesterPassword = apiRequest.requesterPassword match {
+ case Some(password) => Password.create(password).fold(error => throw error, value => value)
+ case None => throw BadRequestException("The requester's password is missing.")
+ }
+ val changedPassword = apiRequest.newPassword match {
+ case Some(password) => Password.create(password).fold(error => throw error, value => value)
+ case None => throw BadRequestException("The new password is missing.")
+ }
val requestMessage: Future[UsersResponderRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserChangePasswordRequestADM(
- userIri = userIri,
- changeUserRequest = apiRequest,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserChangePasswordRequestADM(
+ userIri = checkedUserIri,
+ userUpdatePasswordPayload = UserUpdatePasswordPayloadADM(requesterPassword, changedPassword),
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -325,36 +383,43 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: Change user's status.
- */
+ * API MAY CHANGE: Change user's status.
+ */
@ApiMayChange
private def changeUserStatus(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "iri" / Segment / "Status") { value =>
+ path(UsersBasePath / "iri" / Segment / "Status") { userIri =>
put {
entity(as[ChangeUserApiRequestADM]) { apiRequest => requestContext =>
- val userIri =
- stringFormatter.validateAndEscapeUserIri(value, throw BadRequestException(s"Invalid user IRI $value"))
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- if (userIri.equals(KnoraSystemInstances.Users.SystemUser.id) || userIri.equals(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
throw BadRequestException("Changes to built-in users are not allowed.")
}
- /* the api request is already checked at time of creation. see case class. */
+ val newStatus = apiRequest.status match {
+ case Some(status) => Status.create(status).fold(error => throw error, value => value)
+ case None => throw BadRequestException("The status is missing.")
+ }
val requestMessage: Future[UsersResponderRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserChangeStatusRequestADM(
- userIri = userIri,
- changeUserRequest = apiRequest,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserChangeStatusRequestADM(
+ userIri = checkedUserIri,
+ status = newStatus,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -369,79 +434,90 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: delete a user identified by iri (change status to false).
- */
+ * API MAY CHANGE: delete a user identified by iri (change status to false).
+ */
@ApiMayChange
private def deleteUser(featureFactoryConfig: FeatureFactoryConfig): Route = path(UsersBasePath / "iri" / Segment) {
- value =>
+ userIri =>
delete { requestContext =>
- {
- val userIri =
- stringFormatter.validateAndEscapeUserIri(value, throw BadRequestException(s"Invalid user IRI $value"))
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
- if (userIri.equals(KnoraSystemInstances.Users.SystemUser.id) || userIri.equals(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
- throw BadRequestException("Changes to built-in users are not allowed.")
- }
-
- /* update existing user's status to false */
- val requestMessage: Future[UserChangeStatusRequestADM] = for {
- requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserChangeStatusRequestADM(
- userIri = userIri,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(false)),
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- RouteUtilADM.runJsonRoute(
- requestMessageF = requestMessage,
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig,
- settings = settings,
- responderManager = responderManager,
- log = log
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
)
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
}
+
+ /* update existing user's status to false */
+ val status = Status.create(false).fold(error => throw error, value => value)
+
+ val requestMessage: Future[UserChangeStatusRequestADM] = for {
+ requestingUser <- getUserADM(
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserChangeStatusRequestADM(
+ userIri = checkedUserIri,
+ status = status,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
+
+ RouteUtilADM.runJsonRoute(
+ requestMessageF = requestMessage,
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig,
+ settings = settings,
+ responderManager = responderManager,
+ log = log
+ )
}
}
/**
- * API MAY CHANGE: Change user's SystemAdmin membership.
- */
+ * API MAY CHANGE: Change user's SystemAdmin membership.
+ */
@ApiMayChange
- private def changeUserSytemAdminMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
- path(UsersBasePath / "iri" / Segment / "SystemAdmin") { value =>
+ private def changeUserSystemAdminMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
+ path(UsersBasePath / "iri" / Segment / "SystemAdmin") { userIri =>
put {
entity(as[ChangeUserApiRequestADM]) { apiRequest => requestContext =>
- val userIri =
- stringFormatter.validateAndEscapeUserIri(value, throw BadRequestException(s"Invalid user IRI $value"))
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- if (userIri.equals(KnoraSystemInstances.Users.SystemUser.id) || userIri.equals(
- KnoraSystemInstances.Users.AnonymousUser.id)) {
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
throw BadRequestException("Changes to built-in users are not allowed.")
}
- /* the api request is already checked at time of creation. see case class. */
+ val newSystemAdmin = apiRequest.systemAdmin match {
+ case Some(systemAdmin) => SystemAdmin.create(systemAdmin).fold(error => throw error, value => value)
+ case None => throw BadRequestException("The systemAdmin is missing.")
+ }
val requestMessage: Future[UsersResponderRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserChangeSystemAdminMembershipStatusRequestADM(
- userIri = userIri,
- changeUserRequest = apiRequest,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserChangeSystemAdminMembershipStatusRequestADM(
+ userIri = checkedUserIri,
+ systemAdmin = newSystemAdmin,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -456,26 +532,27 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: get user's project memberships
- */
+ * API MAY CHANGE: get user's project memberships
+ */
@ApiMayChange
private def getUsersProjectMemberships(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-memberships") { userIri =>
get { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
val requestMessage: Future[UserProjectMembershipsGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectMembershipsGetRequestADM(
- userIri = checkedUserIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectMembershipsGetRequestADM(
+ userIri = checkedUserIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -489,31 +566,43 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: add user to project
- */
+ * API MAY CHANGE: add user to project
+ */
@ApiMayChange
private def addUserToProjectMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-memberships" / Segment) { (userIri, projectIri) =>
post { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
+
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
val checkedProjectIri =
- stringFormatter.validateAndEscapeProjectIri(projectIri,
- throw BadRequestException(s"Invalid project IRI $projectIri"))
+ stringFormatter.validateAndEscapeProjectIri(
+ projectIri,
+ throw BadRequestException(s"Invalid project IRI $projectIri")
+ )
val requestMessage: Future[UserProjectMembershipAddRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectMembershipAddRequestADM(
- userIri = checkedUserIri,
- projectIri = checkedProjectIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectMembershipAddRequestADM(
+ userIri = checkedUserIri,
+ projectIri = checkedProjectIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -527,31 +616,43 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: remove user from project (and all groups belonging to this project)
- */
+ * API MAY CHANGE: remove user from project (and all groups belonging to this project)
+ */
@ApiMayChange
private def removeUserFromProjectMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-memberships" / Segment) { (userIri, projectIri) =>
delete { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
+
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
val checkedProjectIri =
- stringFormatter.validateAndEscapeProjectIri(projectIri,
- throw BadRequestException(s"Invalid project IRI $projectIri"))
+ stringFormatter.validateAndEscapeProjectIri(
+ projectIri,
+ throw BadRequestException(s"Invalid project IRI $projectIri")
+ )
val requestMessage: Future[UserProjectMembershipRemoveRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectMembershipRemoveRequestADM(
- userIri = checkedUserIri,
- projectIri = checkedProjectIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectMembershipRemoveRequestADM(
+ userIri = checkedUserIri,
+ projectIri = checkedProjectIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -565,27 +666,28 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: get user's project admin memberships
- */
+ * API MAY CHANGE: get user's project admin memberships
+ */
@ApiMayChange
private def getUsersProjectAdminMemberships(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-admin-memberships") { userIri =>
get { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
val requestMessage: Future[UserProjectAdminMembershipsGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectAdminMembershipsGetRequestADM(
- userIri = checkedUserIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectAdminMembershipsGetRequestADM(
+ userIri = checkedUserIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -599,71 +701,93 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: add user to project admin
- */
+ * API MAY CHANGE: add user to project admin
+ */
@ApiMayChange
private def addUserToProjectAdminMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-admin-memberships" / Segment) { (userIri, projectIri) =>
- post {
- /* */
- requestContext =>
- val checkedUserIri =
- stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- val checkedProjectIri =
- stringFormatter.validateAndEscapeProjectIri(projectIri,
- throw BadRequestException(s"Invalid project IRI $projectIri"))
+ post { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
- val requestMessage: Future[UserProjectAdminMembershipAddRequestADM] = for {
- requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectAdminMembershipAddRequestADM(
- userIri = checkedUserIri,
- projectIri = checkedProjectIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ val checkedUserIri =
+ stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
- RouteUtilADM.runJsonRoute(
- requestMessageF = requestMessage,
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig,
- settings = settings,
- responderManager = responderManager,
- log = log
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
)
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
+ val checkedProjectIri =
+ stringFormatter.validateAndEscapeProjectIri(
+ projectIri,
+ throw BadRequestException(s"Invalid project IRI $projectIri")
+ )
+
+ val requestMessage: Future[UserProjectAdminMembershipAddRequestADM] = for {
+ requestingUser <- getUserADM(
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectAdminMembershipAddRequestADM(
+ userIri = checkedUserIri,
+ projectIri = checkedProjectIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
+
+ RouteUtilADM.runJsonRoute(
+ requestMessageF = requestMessage,
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig,
+ settings = settings,
+ responderManager = responderManager,
+ log = log
+ )
}
}
/**
- * API MAY CHANGE: remove user from project admin membership
- */
+ * API MAY CHANGE: remove user from project admin membership
+ */
@ApiMayChange
private def removeUserFromProjectAdminMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "project-admin-memberships" / Segment) { (userIri, projectIri) =>
delete { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
+
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
val checkedProjectIri =
- stringFormatter.validateAndEscapeProjectIri(projectIri,
- throw BadRequestException(s"Invalid project IRI $projectIri"))
+ stringFormatter.validateAndEscapeProjectIri(
+ projectIri,
+ throw BadRequestException(s"Invalid project IRI $projectIri")
+ )
val requestMessage: Future[UserProjectAdminMembershipRemoveRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserProjectAdminMembershipRemoveRequestADM(
- userIri = checkedUserIri,
- projectIri = checkedProjectIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserProjectAdminMembershipRemoveRequestADM(
+ userIri = checkedUserIri,
+ projectIri = checkedProjectIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -677,26 +801,27 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: get user's group memberships
- */
+ * API MAY CHANGE: get user's group memberships
+ */
@ApiMayChange
private def getUsersGroupMemberships(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "group-memberships") { userIri =>
get { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
val requestMessage: Future[UserGroupMembershipsGetRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGroupMembershipsGetRequestADM(
- userIri = checkedUserIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGroupMembershipsGetRequestADM(
+ userIri = checkedUserIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -710,30 +835,40 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: add user to group
- */
+ * API MAY CHANGE: add user to group
+ */
@ApiMayChange
private def addUserToGroupMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "group-memberships" / Segment) { (userIri, groupIri) =>
post { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
+
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
val checkedGroupIri =
stringFormatter.validateAndEscapeIri(groupIri, throw BadRequestException(s"Invalid group IRI $groupIri"))
val requestMessage: Future[UserGroupMembershipAddRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGroupMembershipAddRequestADM(
- userIri = checkedUserIri,
- groupIri = checkedGroupIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGroupMembershipAddRequestADM(
+ userIri = checkedUserIri,
+ groupIri = checkedGroupIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
@@ -747,30 +882,40 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
/**
- * API MAY CHANGE: remove user from group
- */
+ * API MAY CHANGE: remove user from group
+ */
@ApiMayChange
private def removeUserFromGroupMembership(featureFactoryConfig: FeatureFactoryConfig): Route =
path(UsersBasePath / "iri" / Segment / "group-memberships" / Segment) { (userIri, groupIri) =>
delete { requestContext =>
+ if (userIri.isEmpty) throw BadRequestException("User IRI cannot be empty")
+
val checkedUserIri =
stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri"))
+
+ if (
+ checkedUserIri.equals(KnoraSystemInstances.Users.SystemUser.id) || checkedUserIri.equals(
+ KnoraSystemInstances.Users.AnonymousUser.id
+ )
+ ) {
+ throw BadRequestException("Changes to built-in users are not allowed.")
+ }
+
val checkedGroupIri =
stringFormatter.validateAndEscapeIri(groupIri, throw BadRequestException(s"Invalid group IRI $groupIri"))
val requestMessage: Future[UserGroupMembershipRemoveRequestADM] = for {
requestingUser <- getUserADM(
- requestContext = requestContext,
- featureFactoryConfig = featureFactoryConfig
- )
- } yield
- UserGroupMembershipRemoveRequestADM(
- userIri = checkedUserIri,
- groupIri = checkedGroupIri,
- featureFactoryConfig = featureFactoryConfig,
- requestingUser = requestingUser,
- apiRequestID = UUID.randomUUID()
- )
+ requestContext = requestContext,
+ featureFactoryConfig = featureFactoryConfig
+ )
+ } yield UserGroupMembershipRemoveRequestADM(
+ userIri = checkedUserIri,
+ groupIri = checkedGroupIri,
+ featureFactoryConfig = featureFactoryConfig,
+ requestingUser = requestingUser,
+ apiRequestID = UUID.randomUUID()
+ )
RouteUtilADM.runJsonRoute(
requestMessageF = requestMessage,
diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUser.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUser.scala.txt
index c2f017acb2..d0a11eba8f 100644
--- a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUser.scala.txt
+++ b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUser.scala.txt
@@ -31,7 +31,6 @@
* @param maybeEmail the new optional value for email.
* @param maybeGivenName the new optional value for given name.
* @param maybeFamilyName the new optional value for family name.
- * @param maybePassword the new optional value for value for password.
* @param maybeStatus the new optional value for status.
* @param maybeLang the new optional value for lang.
* @param maybeProjects the new optional value for projects.
@@ -46,7 +45,6 @@
maybeEmail: Option[String],
maybeGivenName: Option[String],
maybeFamilyName: Option[String],
- maybePassword: Option[String],
maybeStatus: Option[Boolean],
maybeLang: Option[String],
maybeProjects: Option[Seq[IRI]],
@@ -80,10 +78,6 @@ DELETE {
?user knora-admin:familyName ?currentFamilyName .
}
- @if(maybePassword.nonEmpty) {
- ?user knora-admin:password ?currentPassword .
- }
-
@if(maybeStatus.nonEmpty) {
?user knora-admin:status ?currentStatus .
}
@@ -128,10 +122,6 @@ DELETE {
?user knora-admin:familyName "@maybeFamilyName.get"^^xsd:string .
}
- @if(maybePassword.nonEmpty) {
- ?user knora-admin:password "@maybePassword.get"^^xsd:string .
- }
-
@if(maybeStatus.nonEmpty) {
?user knora-admin:status "@maybeStatus.get"^^xsd:boolean .
}
@@ -193,8 +183,6 @@ WHERE {
?user knora-admin:familyName ?currentFamilyName .
- ?user knora-admin:password ?currentPassword .
-
?user knora-admin:status ?currentStatus .
?user knora-admin:preferredLanguage ?currentPreferredLanguage .
diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUserPassword.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUserPassword.scala.txt
new file mode 100644
index 0000000000..bb709735ec
--- /dev/null
+++ b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateUserPassword.scala.txt
@@ -0,0 +1,85 @@
+@*
+ * Copyright © 2015-2021 the contributors (see Contributors.md).
+ *
+ * This file is part of Knora.
+ *
+ * Knora is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Knora is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with Knora. If not, see .
+ *@
+
+@import org.knora.webapi.IRI
+@import org.knora.webapi.messages.util.KnoraSystemInstances
+
+@**
+ * Updates an existing user with the provided values.
+ *
+ * @param dataNamedGraph the named graph to update.
+ * @param triplestore the name of the triplestore being used. The template uses this value to exclude inferred
+ results from the WHERE clause of the update.
+ * @param userIri the IRI of the user we want to update.
+ * @param newPassword the new optional value for value for password.
+ *@
+@(adminNamedGraphIri: IRI,
+ triplestore: String,
+ userIri: IRI,
+ newPassword: String)
+
+PREFIX rdf:
+PREFIX rdfs:
+PREFIX xsd:
+PREFIX knora-admin:
+
+WITH <@adminNamedGraphIri>
+DELETE {
+
+ @* Delete current value, for which we have a new one. *@
+
+ @if(newPassword.nonEmpty) {
+ ?user knora-admin:password ?currentPassword .
+ }
+
+} INSERT {
+
+ @* Add the new value. *@
+
+ @if(newPassword.nonEmpty) {
+ ?user knora-admin:password "@newPassword"^^xsd:string .
+ }
+
+}
+
+@*
+
+GraphDB's consistency checking requires reasoning, but reasoning interferes with certain things
+in the WHERE clauses of our SPARQL updates, so we set a GraphDB-specific flag to return only
+explicit statements in the WHERE clause here.
+
+*@
+
+@triplestore match {
+ case "graphdb" | "graphdb-free" => {
+ USING
+ }
+
+ case other => {}
+}
+
+WHERE {
+ BIND(IRI("@userIri") AS ?user)
+
+ @* Get all current defined values. *@
+
+ ?user knora-admin:password ?currentPassword .
+
+ FILTER(!(?user = IRI("@KnoraSystemInstances.Users.AnonymousUser.id") || ?user = IRI("@KnoraSystemInstances.Users.SystemUser.id")))
+}
diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/admin/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/e2e/admin/BUILD.bazel
index 8b4809112d..ce65f52cd8 100644
--- a/webapi/src/test/scala/org/knora/webapi/e2e/admin/BUILD.bazel
+++ b/webapi/src/test/scala/org/knora/webapi/e2e/admin/BUILD.bazel
@@ -99,7 +99,7 @@ scala_test(
scala_test(
name = "UsersADME2ESpec",
- size = "small",
+ size = "medium",
srcs = [
"UsersADME2ESpec.scala",
"//webapi/src/test/scala/org/knora/webapi/messages:SessionMessagesV1",
diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala
index 2f225113e9..e55e8edda3 100644
--- a/webapi/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala
+++ b/webapi/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala
@@ -78,35 +78,30 @@ class UsersADME2ESpec
"test"
)
- private val inactiveUserEmailEnc =
- java.net.URLEncoder.encode(SharedTestDataV1.inactiveUser.userData.email.get, "utf-8")
-
private val normalUserIri = SharedTestDataV1.normalUser.userData.user_id.get
private val normalUserIriEnc = java.net.URLEncoder.encode(normalUserIri, "utf-8")
private val multiUserIri = SharedTestDataV1.multiuserUser.userData.user_id.get
private val multiUserIriEnc = java.net.URLEncoder.encode(multiUserIri, "utf-8")
- private val wrongEmail = "wrong@example.com"
- private val wrongEmailEnc = java.net.URLEncoder.encode(wrongEmail, "utf-8")
-
- private val testPass = java.net.URLEncoder.encode("test", "utf-8")
- private val wrongPass = java.net.URLEncoder.encode("wrong", "utf-8")
-
private val imagesProjectIri = SharedTestDataADM.imagesProject.id
private val imagesProjectIriEnc = java.net.URLEncoder.encode(imagesProjectIri, "utf-8")
private val imagesReviewerGroupIri = SharedTestDataADM.imagesReviewerGroup.id
private val imagesReviewerGroupIriEnc = java.net.URLEncoder.encode(imagesReviewerGroupIri, "utf-8")
+ private val customUserIri = "http://rdfh.ch/users/prWbAoyJA7fECqhKwhSUtQ"
+ private val otherCustomUserIri = "http://rdfh.ch/users/prWbAoyJA7fECqhKohSUtQ"
+
+ private val donaldIri = new MutableTestIri
+ private val systemUserIriEncoded = java.net.URLEncoder.encode(KnoraSystemInstances.Users.SystemUser.id, "utf-8")
+
// Directory path for generated client test data
private val clientTestDataPath: Seq[String] = Seq("admin", "users")
// Collects client test data
private val clientTestDataCollector = new ClientTestDataCollector(settings)
- private val customUserIri = "http://rdfh.ch/users/prWbAoyJA7fECqhKwhSUtQ"
-
/**
* Convenience method returning the users project memberships.
*
@@ -176,7 +171,7 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/iri/${rootCreds.urlEncodedIri}") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
response.status should be(StatusCodes.OK)
clientTestDataCollector.addFile(
TestDataFileContent(
@@ -195,7 +190,7 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/email/${rootCreds.urlEncodedEmail}") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
response.status should be(StatusCodes.OK)
}
@@ -204,7 +199,7 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/username/${SharedTestDataADM.rootUser.username}") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
response.status should be(StatusCodes.OK)
}
@@ -335,6 +330,7 @@ class UsersADME2ESpec
}
"given a custom Iri" should {
+
"create a user with the provided custom IRI " in {
val createUserWithCustomIriRequest: String =
s"""{
@@ -405,25 +401,91 @@ class UsersADME2ESpec
errorMessage.contains(s"IRI: '$customUserIri' already exists, try another one.")
invalidIri should be(true)
}
+
}
- "used to modify user information" should {
+ "dealing with special characters" should {
- val donaldIri = new MutableTestIri
+ "escape special characters when creating the user" in {
+ val createUserWithApostropheRequest: String =
+ s"""{
+ | "id": "$otherCustomUserIri",
+ | "username": "userWithApostrophe",
+ | "email": "userWithApostrophe@example.org",
+ | "givenName": "M\\"Given 'Name",
+ | "familyName": "M\\tFamily Name",
+ | "password": "test",
+ | "status": true,
+ | "lang": "en",
+ | "systemAdmin": false
+ |}""".stripMargin
- "create the user if the supplied email is unique " in {
+ val request = Post(baseApiUrl + s"/admin/users",
+ HttpEntity(ContentTypes.`application/json`, createUserWithApostropheRequest))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.OK)
+
+ val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
+
+ //check that the special characters were escaped correctly
+ result.id should equal(otherCustomUserIri)
+ result.givenName should equal("M\"Given 'Name")
+ result.familyName should equal("M\tFamily Name")
+
+ }
+
+ "escape special characters when updating the user" in {
+ val updateUserRequest: String =
+ s"""{
+ | "givenName": "Updated\\tGivenName",
+ | "familyName": "Updated\\"FamilyName"
+ |}""".stripMargin
+
+ val userIriEncoded = java.net.URLEncoder.encode(otherCustomUserIri, "utf-8")
+ val request = Put(baseApiUrl + s"/admin/users/iri/$userIriEncoded/BasicUserInformation",
+ HttpEntity(ContentTypes.`application/json`, updateUserRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.OK)
+
+ val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
+ result.givenName should be("Updated\tGivenName")
+ result.familyName should be("Updated\"FamilyName")
+ }
+
+ "return the special characters correctly when getting a user with special characters in givenName and familyName" in {
+ val userIriEncoded = java.net.URLEncoder.encode(otherCustomUserIri, "utf-8")
+
+ val request = Get(baseApiUrl + s"/admin/users/iri/$userIriEncoded") ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.OK)
+
+ val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
+ result.givenName should be("Updated\tGivenName")
+ result.familyName should be("Updated\"FamilyName")
+ }
+
+ }
+
+ "used to create a user" should {
+
+ "create the user if the supplied email and username are unique " in {
val createUserRequest: String =
s"""{
- | "username": "donald.duck",
- | "email": "donald.duck@example.org",
- | "givenName": "Donald",
- | "familyName": "Duck",
- | "password": "test",
- | "status": true,
- | "lang": "en",
- | "systemAdmin": false
- |}""".stripMargin
+ | "username": "donald.duck",
+ | "email": "donald.duck@example.org",
+ | "givenName": "Donald",
+ | "familyName": "Duck",
+ | "password": "test",
+ | "status": true,
+ | "lang": "en",
+ | "systemAdmin": false
+ |}""".stripMargin
clientTestDataCollector.addFile(
TestDataFileContent(
@@ -438,7 +500,6 @@ class UsersADME2ESpec
val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
@@ -450,7 +511,6 @@ class UsersADME2ESpec
result.lang should be("en")
donaldIri.set(result.id)
- // log.debug(s"iri: ${donaldIri.get}")
clientTestDataCollector.addFile(
TestDataFileContent(
@@ -464,13 +524,94 @@ class UsersADME2ESpec
)
}
+ "return a 'BadRequest' if the supplied username is not unique " in {
+
+ val createUserRequest: String =
+ s"""{
+ | "username": "donald.duck",
+ | "email": "new.donald.duck@example.org",
+ | "givenName": "NewDonald",
+ | "familyName": "NewDuck",
+ | "password": "test",
+ | "status": true,
+ | "lang": "en",
+ | "systemAdmin": false
+ |}""".stripMargin
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "create-user-request-duplicate-username",
+ fileExtension = "json"
+ ),
+ text = createUserRequest
+ )
+ )
+ val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.BadRequest)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "create-user-response-duplicate-username",
+ fileExtension = "json"
+ ),
+ text = responseToString(response)
+ )
+ )
+ }
+
+ "return a 'BadRequest' if the supplied email is not unique " in {
+
+ val createUserRequest: String =
+ s"""{
+ | "username": "new.donald.duck",
+ | "email": "donald.duck@example.org",
+ | "givenName": "NewDonald",
+ | "familyName": "NewDuck",
+ | "password": "test",
+ | "status": true,
+ | "lang": "en",
+ | "systemAdmin": false
+ |}""".stripMargin
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "create-user-request-duplicate-email",
+ fileExtension = "json"
+ ),
+ text = createUserRequest
+ )
+ )
+ val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.BadRequest)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "create-user-response-duplicate-email",
+ fileExtension = "json"
+ ),
+ text = responseToString(response)
+ )
+ )
+ }
+
"authenticate the newly created user using HttpBasicAuth" in {
val request = Get(baseApiUrl + s"/v2/authentication") ~> addCredentials(
BasicHttpCredentials("donald.duck@example.org", "test"))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
}
@@ -487,10 +628,13 @@ class UsersADME2ESpec
val request = Post(baseApiUrl + s"/v2/authentication", HttpEntity(ContentTypes.`application/json`, params))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
}
+ }
+
+ "used to modify user information" should {
+
"update the user's basic information" in {
val updateUserRequest: String =
@@ -518,7 +662,6 @@ class UsersADME2ESpec
HttpEntity(ContentTypes.`application/json`, updateUserRequest)) ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
@@ -540,6 +683,64 @@ class UsersADME2ESpec
)
}
+ "return 'BadRequest' if user IRI is None and 'NotFound' if user IRI is '' in update user request" in {
+
+ val updateUserRequest: String =
+ s"""{
+ | "username": "donald.without.iri.duck"
+ |}""".stripMargin
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "update-user-request-without-iri",
+ fileExtension = "json"
+ ),
+ text = updateUserRequest
+ )
+ )
+
+ val missingUserIri = ""
+ val request = Put(baseApiUrl + s"/admin/users/iri/$missingUserIri/BasicUserInformation",
+ HttpEntity(ContentTypes.`application/json`, updateUserRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ response.status should be(StatusCodes.NotFound)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "update-user-response-without-iri-1",
+ fileExtension = "json"
+ ),
+ text = responseToString(response)
+ )
+ )
+
+ val missingUserIriNone = None
+ val request2 = Put(baseApiUrl + s"/admin/users/iri/$missingUserIriNone/BasicUserInformation",
+ HttpEntity(ContentTypes.`application/json`, updateUserRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response2: HttpResponse = singleAwaitingRequest(request2)
+
+ response2.status should be(StatusCodes.BadRequest)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "update-user-response-without-iri-2",
+ fileExtension = "json"
+ ),
+ text = responseToString(response2)
+ )
+ )
+
+ }
+
"update the user's password (by himself)" in {
val changeUserPasswordRequest: String =
@@ -609,6 +810,92 @@ class UsersADME2ESpec
response2.status should be(StatusCodes.OK)
}
+ "return 'BadRequest' if new password in change password request is missing" in {
+
+ val changeUserPasswordRequest: String =
+ s"""{
+ | "requesterPassword": "test"
+ |}""".stripMargin
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "incomplete-update-user-password-request",
+ fileExtension = "json"
+ ),
+ text = changeUserPasswordRequest
+ )
+ )
+
+ val request1 = Put(baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/Password",
+ HttpEntity(ContentTypes.`application/json`, changeUserPasswordRequest)) ~> addCredentials(
+ BasicHttpCredentials(normalUserCreds.email, "test")) // requester's password
+ val response1: HttpResponse = singleAwaitingRequest(request1)
+
+ response1.status should be(StatusCodes.BadRequest)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "incomplete-update-user-password-response",
+ fileExtension = "json"
+ ),
+ text = responseToString(response1)
+ )
+ )
+
+ // check that the password was not changed, i.e. the old one is still accepted
+ val request2 = Get(baseApiUrl + s"/v2/authentication") ~> addCredentials(
+ BasicHttpCredentials(normalUserCreds.email, "test654321")) // old password (taken from previous test)
+ val response2: HttpResponse = singleAwaitingRequest(request2)
+ response2.status should be(StatusCodes.OK)
+ }
+
+ "return 'BadRequest' if requester's password in change password request is missing" in {
+
+ val changeUserPasswordRequest: String =
+ s"""{
+ | "newPassword": "testABC"
+ |}""".stripMargin
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "incomplete-update-user-password-request-2",
+ fileExtension = "json"
+ ),
+ text = changeUserPasswordRequest
+ )
+ )
+
+ val request1 = Put(baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/Password",
+ HttpEntity(ContentTypes.`application/json`, changeUserPasswordRequest)) ~> addCredentials(
+ BasicHttpCredentials(normalUserCreds.email, "test")) // requester's password
+ val response1: HttpResponse = singleAwaitingRequest(request1)
+
+ response1.status should be(StatusCodes.BadRequest)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "incomplete-update-user-password-response-2",
+ fileExtension = "json"
+ ),
+ text = responseToString(response1)
+ )
+ )
+
+ // check that the password was not changed, i.e. the old one is still accepted
+ val request2 = Get(baseApiUrl + s"/v2/authentication") ~> addCredentials(
+ BasicHttpCredentials(normalUserCreds.email, "test654321")) // old password
+ val response2: HttpResponse = singleAwaitingRequest(request2)
+ response2.status should be(StatusCodes.OK)
+ }
+
"change user's status" in {
val changeUserStatusRequest: String =
s"""{
@@ -630,7 +917,6 @@ class UsersADME2ESpec
HttpEntity(ContentTypes.`application/json`, changeUserStatusRequest)) ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
@@ -647,6 +933,23 @@ class UsersADME2ESpec
)
}
+ "return 'BadRequest' if more than 1 parameter is provided in update status request" in {
+
+ val updateUserRequest: String =
+ s"""{
+ | "status": false,
+ | "username": "parameterDuck"
+ |}""".stripMargin
+
+ val donaldIriEncoded = java.net.URLEncoder.encode(donaldIri.get, "utf-8")
+ val request = Put(baseApiUrl + s"/admin/users/iri/$donaldIriEncoded/Status",
+ HttpEntity(ContentTypes.`application/json`, updateUserRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+ response.status should be(StatusCodes.BadRequest)
+
+ }
+
"update the user's system admin membership status" in {
val changeUserSystemAdminMembershipRequest: String =
s"""{
@@ -669,14 +972,12 @@ class UsersADME2ESpec
HttpEntity(ContentTypes.`application/json`, changeUserSystemAdminMembershipRequest)) ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
response.status should be(StatusCodes.OK)
val result: UserADM = AkkaHttpUtils.httpResponseToJson(response).fields("user").convertTo[UserADM]
result.permissions.groupsPerProject
.get("http://www.knora.org/ontology/knora-admin#SystemProject")
.head should equal(List("http://www.knora.org/ontology/knora-admin#SystemAdmin"))
- // log.debug(jsonResult)
clientTestDataCollector.addFile(
TestDataFileContent(
@@ -689,12 +990,30 @@ class UsersADME2ESpec
)
)
+ // Throw BadRequest exception if user is built-in user
+ val badRequest = Put(
+ baseApiUrl + s"/admin/users/iri/$systemUserIriEncoded/SystemAdmin",
+ HttpEntity(ContentTypes.`application/json`, changeUserSystemAdminMembershipRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val badResponse: HttpResponse = singleAwaitingRequest(badRequest)
+ badResponse.status should be(StatusCodes.BadRequest)
}
- "not allow changing the system user" in {
+ "not allow updating the system user's system admin membership status" in {
+ val changeUserSystemAdminMembershipRequest: String =
+ s"""{
+ | "systemAdmin": true
+ |}""".stripMargin
- val systemUserIriEncoded = java.net.URLEncoder.encode(KnoraSystemInstances.Users.SystemUser.id, "utf-8")
+ val request = Put(
+ baseApiUrl + s"/admin/users/iri/$systemUserIriEncoded/SystemAdmin",
+ HttpEntity(ContentTypes.`application/json`, changeUserSystemAdminMembershipRequest)) ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+ response.status should be(StatusCodes.BadRequest)
+ }
+ "not allow changing the system user's status" in {
val params =
s"""
{
@@ -709,7 +1028,7 @@ class UsersADME2ESpec
response.status should be(StatusCodes.BadRequest)
}
- "not allow changing the anonymous user" in {
+ "not allow changing the anonymous user's status" in {
val anonymousUserIriEncoded = java.net.URLEncoder.encode(KnoraSystemInstances.Users.AnonymousUser.id, "utf-8")
@@ -747,8 +1066,6 @@ class UsersADME2ESpec
}
"not allow deleting the system user" in {
- val systemUserIriEncoded = java.net.URLEncoder.encode(KnoraSystemInstances.Users.SystemUser.id, "utf-8")
-
val request = Delete(baseApiUrl + s"/admin/users/iri/$systemUserIriEncoded") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
@@ -772,7 +1089,7 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/iri/$multiUserIriEnc/project-memberships") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val projects: Seq[ProjectADM] =
@@ -797,6 +1114,7 @@ class UsersADME2ESpec
}
"used to modify project membership" should {
+
"add user to project" in {
val membershipsBeforeUpdate = getUserProjectMemberships(normalUserCreds.userIri, rootCreds)
membershipsBeforeUpdate should equal(Seq())
@@ -805,7 +1123,7 @@ class UsersADME2ESpec
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/project-memberships/$imagesProjectIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserProjectMemberships(normalUserIri, rootCreds)
@@ -823,6 +1141,32 @@ class UsersADME2ESpec
)
}
+ "don't add user to project if user is already a member" in {
+ val membershipsBeforeTryUpdate = getUserProjectMemberships(normalUserCreds.userIri, rootCreds)
+
+ val request = Post(
+ baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/project-memberships/$imagesProjectIriEnc") ~> addCredentials(
+ BasicHttpCredentials(rootCreds.email, rootCreds.password))
+ val response: HttpResponse = singleAwaitingRequest(request)
+
+ assert(response.status === StatusCodes.BadRequest)
+
+ // verify that users's project memberships weren't changed
+ val membershipsAfterTryUpdate = getUserProjectMemberships(normalUserIri, rootCreds)
+ membershipsAfterTryUpdate should equal(membershipsBeforeTryUpdate)
+
+ clientTestDataCollector.addFile(
+ TestDataFileContent(
+ filePath = TestDataFilePath(
+ directoryPath = clientTestDataPath,
+ filename = "user-already-member-of-project-response",
+ fileExtension = "json"
+ ),
+ text = responseToString(response)
+ )
+ )
+ }
+
"remove user from project" in {
val membershipsBeforeUpdate = getUserProjectMemberships(normalUserCreds.userIri, rootCreds)
@@ -832,7 +1176,7 @@ class UsersADME2ESpec
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/project-memberships/$imagesProjectIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserProjectMemberships(normalUserIri, rootCreds)
@@ -849,6 +1193,7 @@ class UsersADME2ESpec
)
)
}
+
}
"used to query project admin group memberships" should {
@@ -857,7 +1202,6 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/iri/$multiUserIriEnc/project-admin-memberships") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
assert(response.status === StatusCodes.OK)
val projects: Seq[ProjectADM] =
@@ -879,24 +1223,24 @@ class UsersADME2ESpec
)
)
}
+
}
"used to modify project admin group membership" should {
"add user to project admin group" in {
val membershipsBeforeUpdate = getUserProjectAdminMemberships(normalUserCreds.userIri, rootCreds)
- //log.debug(s"membershipsBeforeUpdate: $membershipsBeforeUpdate")
membershipsBeforeUpdate should equal(Seq())
val request = Post(
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/project-admin-memberships/$imagesProjectIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- //log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserProjectAdminMemberships(normalUserCreds.userIri, rootCreds)
- //log.debug(s"membershipsAfterUpdate: $membershipsAfterUpdate")
+
membershipsAfterUpdate should equal(Seq(SharedTestDataADM.imagesProject))
clientTestDataCollector.addFile(
@@ -914,18 +1258,18 @@ class UsersADME2ESpec
"remove user from project admin group" in {
val membershipsBeforeUpdate = getUserProjectAdminMemberships(normalUserCreds.userIri, rootCreds)
- // log.debug(s"membershipsBeforeUpdate: $membershipsBeforeUpdate")
+
membershipsBeforeUpdate should equal(Seq(SharedTestDataADM.imagesProject))
val request = Delete(
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/project-admin-memberships/$imagesProjectIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserProjectAdminMemberships(normalUserCreds.userIri, rootCreds)
- // log.debug(s"membershipsAfterUpdate: $membershipsAfterUpdate")
+
membershipsAfterUpdate should equal(Seq.empty[ProjectADM])
clientTestDataCollector.addFile(
@@ -948,7 +1292,7 @@ class UsersADME2ESpec
val request = Get(baseApiUrl + s"/admin/users/iri/$multiUserIriEnc/group-memberships") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val groups: Seq[GroupADM] =
@@ -969,6 +1313,7 @@ class UsersADME2ESpec
)
)
}
+
}
"used to modify group membership" should {
@@ -982,7 +1327,7 @@ class UsersADME2ESpec
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/group-memberships/$imagesReviewerGroupIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserGroupMemberships(normalUserIri, rootCreds)
@@ -1009,7 +1354,7 @@ class UsersADME2ESpec
baseApiUrl + s"/admin/users/iri/${normalUserCreds.urlEncodedIri}/group-memberships/$imagesReviewerGroupIriEnc") ~> addCredentials(
BasicHttpCredentials(rootCreds.email, rootCreds.password))
val response: HttpResponse = singleAwaitingRequest(request)
- // log.debug(s"response: ${response.toString}")
+
assert(response.status === StatusCodes.OK)
val membershipsAfterUpdate = getUserProjectMemberships(normalUserIri, rootCreds)
@@ -1026,6 +1371,8 @@ class UsersADME2ESpec
)
)
}
+
}
+
}
}
diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/BUILD.bazel
index bb6b88088d..599f93fb7d 100644
--- a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/BUILD.bazel
+++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/BUILD.bazel
@@ -21,3 +21,5 @@ scala_test(
"@maven//:org_springframework_security_spring_security_core",
] + BASE_TEST_DEPENDENCIES_WITH_JSON,
)
+
+
diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADMSpec.scala
index 9e3b8efbb8..a71d484e44 100644
--- a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADMSpec.scala
+++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADMSpec.scala
@@ -19,7 +19,7 @@
package org.knora.webapi.messages.admin.responder.usersmessages
-import com.typesafe.config.ConfigFactory
+import com.typesafe.config.{Config, ConfigFactory}
import org.knora.webapi._
import org.knora.webapi.exceptions.BadRequestException
import org.knora.webapi.messages.StringFormatter
@@ -29,14 +29,14 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
object UsersMessagesADMSpec {
- val config = ConfigFactory.parseString("""
+ val config: Config = ConfigFactory.parseString("""
akka.loglevel = "DEBUG"
akka.stdout-loglevel = "DEBUG"
""".stripMargin)
}
/**
- * This spec is used to test subclasses of the [[UsersMessagesADM]] class.
+ * This spec is used to test the [[UserADM]] and [[UserIdentifierADM]] classes.
*/
class UsersMessagesADMSpec extends CoreSpec(UsersMessagesADMSpec.config) {
@@ -171,108 +171,6 @@ class UsersMessagesADMSpec extends CoreSpec(UsersMessagesADMSpec.config) {
}
}
- "The CreateUserApiRequestADM case class" should {
-
- "throw 'BadRequestException' if 'username'is missing" in {
-
- assertThrows[BadRequestException](
- CreateUserApiRequestADM(
- username = "",
- email = "ddd@example.com",
- givenName = "Donald",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- }
-
- "throw 'BadRequestException' if 'email' is missing" in {
-
- assertThrows[BadRequestException](
- CreateUserApiRequestADM(
- username = "ddd",
- email = "",
- givenName = "Donald",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- }
-
- "throw 'BadRequestException' if 'password' is missing" in {
-
- assertThrows[BadRequestException](
- CreateUserApiRequestADM(
- username = "donald.duck",
- email = "donald.duck@example.com",
- givenName = "Donald",
- familyName = "Duck",
- password = "",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- }
-
- "throw 'BadRequestException' if 'givenName' is missing" in {
-
- assertThrows[BadRequestException](
- CreateUserApiRequestADM(
- username = "donald.duck",
- email = "donald.duck@example.com",
- givenName = "",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- }
-
- "throw 'BadRequestException' if 'familyName' is missing" in {
-
- assertThrows[BadRequestException](
- CreateUserApiRequestADM(
- username = "donald.duck",
- email = "donald.duck@example.com",
- givenName = "Donald",
- familyName = "",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- }
-
- "return 'BadRequest' if the supplied 'id' is not a valid IRI" in {
-
- val caught = intercept[BadRequestException](
- CreateUserApiRequestADM(
- id = Some("invalid-user-IRI"),
- username = "userWithInvalidCustomIri",
- email = "userWithInvalidCustomIri@example.org",
- givenName = "a user",
- familyName = "with an invalid custom Iri",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- )
- )
- assert(caught.getMessage === "Invalid user IRI")
- }
-
- }
-
"The UserIdentifierADM case class" should {
"return the identifier type" in {
@@ -334,4 +232,64 @@ class UsersMessagesADMSpec extends CoreSpec(UsersMessagesADMSpec.config) {
}
}
+
+ "The ChangeUserApiRequestADM case class" should {
+
+ "throw a BadRequestException if number of parameters is wrong" in {
+
+ // all parameters are None
+ assertThrows[BadRequestException](
+ ChangeUserApiRequestADM()
+ )
+
+ val errorNoParameters = the[BadRequestException] thrownBy ChangeUserApiRequestADM()
+ errorNoParameters.getMessage should equal("No data sent in API request.")
+
+ // more than one parameter for status update
+ assertThrows[BadRequestException](
+ ChangeUserApiRequestADM(status = Some(true), systemAdmin = Some(true))
+ )
+
+ val errorTooManyParametersStatusUpdate = the[BadRequestException] thrownBy ChangeUserApiRequestADM(status =
+ Some(true),
+ systemAdmin =
+ Some(true))
+ errorTooManyParametersStatusUpdate.getMessage should equal("Too many parameters sent for change request.")
+
+ // more than one parameter for systemAdmin update
+ assertThrows[BadRequestException](
+ ChangeUserApiRequestADM(systemAdmin = Some(true), status = Some(true))
+ )
+
+ val errorTooManyParametersSystemAdminUpdate = the[BadRequestException] thrownBy ChangeUserApiRequestADM(
+ systemAdmin = Some(true),
+ status = Some(true))
+ errorTooManyParametersSystemAdminUpdate.getMessage should equal("Too many parameters sent for change request.")
+
+ // more than 5 parameters for basic user information update
+ assertThrows[BadRequestException](
+ ChangeUserApiRequestADM(
+ username = Some("newUsername"),
+ email = Some("newEmail@email.com"),
+ givenName = Some("newGivenName"),
+ familyName = Some("familyName"),
+ lang = Some("en"),
+ status = Some(true),
+ systemAdmin = Some(false)
+ )
+ )
+
+ val errorTooManyParametersBasicInformationUpdate = the[BadRequestException] thrownBy ChangeUserApiRequestADM(
+ username = Some("newUsername"),
+ email = Some("newEmail@email.com"),
+ givenName = Some("newGivenName"),
+ familyName = Some("familyName"),
+ lang = Some("en"),
+ status = Some(true),
+ systemAdmin = Some(false)
+ )
+ errorTooManyParametersBasicInformationUpdate.getMessage should equal(
+ "Too many parameters sent for change request.")
+ }
+ }
}
diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/BUILD.bazel
new file mode 100644
index 0000000000..af90934728
--- /dev/null
+++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/BUILD.bazel
@@ -0,0 +1,23 @@
+package(default_visibility = ["//visibility:public"])
+
+load("@io_bazel_rules_scala//scala:scala.bzl", "scala_test")
+load("//third_party:dependencies.bzl", "ALL_WEBAPI_MAIN_DEPENDENCIES", "BASE_TEST_DEPENDENCIES_WITH_JSON")
+
+scala_test(
+ name = "ValueObjectsADMSpec",
+ size = "small", # 60s
+ srcs = [
+ "ValueObjectsADMSpec.scala",
+ ],
+ data = [
+ "//knora-ontologies",
+ "//test_data",
+ ],
+ jvm_flags = ["-Dconfig.resource=fuseki.conf"],
+ # unused_dependency_checker_mode = "warn",
+ deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [
+ "//webapi:main_library",
+ "//webapi:test_library",
+ "@maven//:org_springframework_security_spring_security_core",
+ ] + BASE_TEST_DEPENDENCIES_WITH_JSON,
+)
diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/ValueObjectsADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/ValueObjectsADMSpec.scala
new file mode 100644
index 0000000000..9edb723765
--- /dev/null
+++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/valueObjects/ValueObjectsADMSpec.scala
@@ -0,0 +1,230 @@
+/*
+ * Copyright © 2015-2021 the contributors (see Contributors.md).
+ *
+ * This file is part of Knora.
+ *
+ * Knora is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Knora is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with Knora. If not, see .
+ */
+
+package org.knora.webapi.messages.admin.responder.valueObjects
+
+import com.typesafe.config.{Config, ConfigFactory}
+import org.knora.webapi.exceptions.BadRequestException
+import org.knora.webapi.messages.StringFormatter
+import org.knora.webapi.messages.admin.responder.usersmessages._
+import org.knora.webapi.{IRI, UnitSpec}
+import org.scalatest.enablers.Messaging.messagingNatureOfThrowable
+
+object ValueObjectsADMSpec {
+ val config: Config = ConfigFactory.parseString("""
+ akka.loglevel = "DEBUG"
+ akka.stdout-loglevel = "DEBUG"
+ """.stripMargin)
+}
+
+/**
+ * This spec is used to test the creation of value objects of the [[ValueObject]] trait.
+ */
+class ValueObjectsADMSpec extends UnitSpec(ValueObjectsADMSpec.config) {
+
+ private implicit val stringFormatter: StringFormatter = StringFormatter.getInstanceForConstantOntologies
+
+ /**
+ * Convenience method returning the UserCreatePayloadADM from the [[CreateUserApiRequestADM]] object
+ *
+ * @param createUserApiRequestADM the [[CreateUserApiRequestADM]] object
+ * @return a [[UserCreatePayloadADM]]
+ */
+ private def createUserCreatePayloadADM(createUserApiRequestADM: CreateUserApiRequestADM): UserCreatePayloadADM =
+ UserCreatePayloadADM.create(
+ id = stringFormatter
+ .validateOptionalUserIri(createUserApiRequestADM.id, throw BadRequestException(s"Invalid user IRI")),
+ username = Username.create(createUserApiRequestADM.username).fold(error => throw error, value => value),
+ email = Email.create(createUserApiRequestADM.email).fold(error => throw error, value => value),
+ givenName = GivenName.create(createUserApiRequestADM.givenName).fold(error => throw error, value => value),
+ familyName = FamilyName.create(createUserApiRequestADM.familyName).fold(error => throw error, value => value),
+ password = Password.create(createUserApiRequestADM.password).fold(error => throw error, value => value),
+ status = Status.create(createUserApiRequestADM.status).fold(error => throw error, value => value),
+ lang = LanguageCode.create(createUserApiRequestADM.lang).fold(error => throw error, value => value),
+ systemAdmin = SystemAdmin.create(createUserApiRequestADM.systemAdmin).fold(error => throw error, value => value)
+ )
+
+ /**
+ * Convenience method returning the [[CreateUserApiRequestADM]] object
+ *
+ * @param id the optional IRI of the user to be created (unique).
+ * @param username the username of the user to be created (unique).
+ * @param email the email of the user to be created (unique).
+ * @param givenName the given name of the user to be created.
+ * @param familyName the family name of the user to be created
+ * @param password the password of the user to be created.
+ * @param status the status of the user to be created (active = true, inactive = false).
+ * @param lang the default language of the user to be created.
+ * @param systemAdmin the system admin membership.
+ * @return a [[UserCreatePayloadADM]]
+ */
+ private def createUserApiRequestADM(
+ id: Option[IRI] = None,
+ username: String = "donald.duck",
+ email: String = "donald.duck@example.com",
+ givenName: String = "Donald",
+ familyName: String = "Duck",
+ password: String = "test",
+ status: Boolean = true,
+ lang: String = "en",
+ systemAdmin: Boolean = false
+ ): CreateUserApiRequestADM =
+ CreateUserApiRequestADM(
+ id = id,
+ username = username,
+ email = email,
+ givenName = givenName,
+ familyName = familyName,
+ password = password,
+ status = status,
+ lang = lang,
+ systemAdmin = systemAdmin
+ )
+
+ "When the UserCreatePayloadADM case class is created it" should {
+ "create a valid UserCreatePayloadADM" in {
+
+ val request = createUserApiRequestADM()
+
+ val userCreatePayloadADM = createUserCreatePayloadADM(request)
+
+ userCreatePayloadADM.id should equal(request.id)
+ userCreatePayloadADM.username.get.value should equal(request.username)
+ userCreatePayloadADM.email.get.value should equal(request.email)
+ userCreatePayloadADM.password.get.value should equal(request.password)
+ userCreatePayloadADM.givenName.get.value should equal(request.givenName)
+ userCreatePayloadADM.familyName.get.value should equal(request.familyName)
+ userCreatePayloadADM.status.get.value should equal(request.status)
+ userCreatePayloadADM.lang.get.value should equal(request.lang)
+ userCreatePayloadADM.systemAdmin.get.value should equal(request.systemAdmin)
+
+ val otherRequest = createUserApiRequestADM(
+ id = Some("http://rdfh.ch/users/notdonald"),
+ username = "not.donald.duck",
+ email = "not.donald.duck@example.com",
+ givenName = "NotDonald",
+ familyName = "NotDuck",
+ password = "notDonaldDuckTest",
+ status = false,
+ lang = "de",
+ systemAdmin = true
+ )
+
+ val otherUserCreatePayloadADM = createUserCreatePayloadADM(otherRequest)
+
+ otherUserCreatePayloadADM.id should equal(otherRequest.id)
+ otherUserCreatePayloadADM.username.get.value should equal(otherRequest.username)
+ otherUserCreatePayloadADM.email.get.value should equal(otherRequest.email)
+ otherUserCreatePayloadADM.password.get.value should equal(otherRequest.password)
+ otherUserCreatePayloadADM.givenName.get.value should equal(otherRequest.givenName)
+ otherUserCreatePayloadADM.familyName.get.value should equal(otherRequest.familyName)
+ otherUserCreatePayloadADM.status.get.value should equal(otherRequest.status)
+ otherUserCreatePayloadADM.lang.get.value should equal(otherRequest.lang)
+ otherUserCreatePayloadADM.systemAdmin.get.value should equal(otherRequest.systemAdmin)
+
+ otherUserCreatePayloadADM.id should not equal request.id
+ otherUserCreatePayloadADM.username.get.value should not equal request.username
+ otherUserCreatePayloadADM.email.get.value should not equal request.email
+ otherUserCreatePayloadADM.password.get.value should not equal request.password
+ otherUserCreatePayloadADM.givenName.get.value should not equal request.givenName
+ otherUserCreatePayloadADM.familyName.get.value should not equal request.familyName
+ otherUserCreatePayloadADM.status.get.value should not equal request.status
+ otherUserCreatePayloadADM.lang.get.value should not equal request.lang
+ otherUserCreatePayloadADM.systemAdmin.get.value should not equal request.systemAdmin
+ }
+
+ "throw 'BadRequestException' if 'username' is missing" in {
+ val request = createUserApiRequestADM(username = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing username"
+ }
+
+ "throw 'BadRequestException' if 'email' is missing" in {
+ val request = createUserApiRequestADM(email = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing email"
+ }
+
+ "throw 'BadRequestException' if 'password' is missing" in {
+ val request = createUserApiRequestADM(password = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing password"
+ }
+
+ "throw 'BadRequestException' if 'givenName' is missing" in {
+ val request = createUserApiRequestADM(givenName = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing given name"
+ }
+
+ "throw 'BadRequestException' if 'familyName' is missing" in {
+ val request = createUserApiRequestADM(familyName = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing family name"
+ }
+
+ "throw 'BadRequestException' if 'lang' is missing" in {
+ val request = createUserApiRequestADM(lang = "")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Missing language code"
+ }
+
+ "throw 'BadRequestException' if the supplied 'id' is not a valid IRI" in {
+ val request = createUserApiRequestADM(id = Some("invalid-iri"))
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Invalid user IRI"
+
+ }
+
+ "throw 'BadRequestException' if 'username' is invalid" in {
+ Set(
+ createUserApiRequestADM(username = "don"), // too short
+ createUserApiRequestADM(username = "asdfoiasdfasdnlasdkjflasdjfaskdjflaskdjfaddssdskdfjs"), // too long
+ createUserApiRequestADM(username = "_donald"), // starts with _
+ createUserApiRequestADM(username = ".donald"), // starts with .
+ createUserApiRequestADM(username = "donald_"), // ends with _
+ createUserApiRequestADM(username = "donald."), // ends with .
+ createUserApiRequestADM(username = "donald__duck"), // contains multiple _
+ createUserApiRequestADM(username = "donald..duck"), // contains multiple .
+ createUserApiRequestADM(username = "donald#duck"), // contains not only alphanumeric characters
+ createUserApiRequestADM(username = "dönälddück") // contains umlaut characters
+ ).map(request =>
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Invalid username"
+ )
+ }
+
+ "throw 'BadRequestException' if 'email' is invalid" in {
+ Set(
+ createUserApiRequestADM(email = "don"), // does not contain @
+ createUserApiRequestADM(email = "don@"), // ends with @
+ createUserApiRequestADM(email = "@don") // starts with @
+ ).map(request =>
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Invalid email"
+ )
+ }
+
+ "throw 'BadRequestException' if 'lang' is invalid" in {
+ val request = createUserApiRequestADM(lang = "xy")
+
+ the[BadRequestException] thrownBy createUserCreatePayloadADM(request) should have message "Invalid language code"
+ }
+
+ }
+
+}
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 b4ba6c3401..0bed67bcd7 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
@@ -20,7 +20,6 @@
package org.knora.webapi.responders.admin
import java.util.UUID
-
import akka.actor.Status.Failure
import akka.testkit.ImplicitSender
import com.typesafe.config.{Config, ConfigFactory}
@@ -29,7 +28,7 @@ import org.knora.webapi.exceptions.{BadRequestException, DuplicateValueException
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.admin.responder.groupsmessages.{GroupMembersGetRequestADM, GroupMembersGetResponseADM}
import org.knora.webapi.messages.admin.responder.projectsmessages._
-import org.knora.webapi.messages.admin.responder.usersmessages._
+import org.knora.webapi.messages.admin.responder.usersmessages.{UserChangeRequestADM, _}
import org.knora.webapi.messages.util.KnoraSystemInstances
import org.knora.webapi.messages.v2.routing.authenticationmessages.KnoraPasswordCredentialsV2
import org.knora.webapi.routing.Authenticator
@@ -47,19 +46,19 @@ object UsersResponderADMSpec {
}
/**
- * This spec is used to test the messages received by the [[UsersResponderADM]] actor.
- */
+ * This spec is used to test the messages received by the [[UsersResponderADM]] actor.
+ */
class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with ImplicitSender with Authenticator {
private val timeout: FiniteDuration = 8.seconds
- private val rootUser = SharedTestDataADM.rootUser
+ private val rootUser = SharedTestDataADM.rootUser
private val anythingAdminUser = SharedTestDataADM.anythingAdminUser
- private val normalUser = SharedTestDataADM.normalUser
+ private val normalUser = SharedTestDataADM.normalUser
private val incunabulaUser = SharedTestDataADM.incunabulaProjectAdminUser
- private val imagesProject = SharedTestDataADM.imagesProject
+ private val imagesProject = SharedTestDataADM.imagesProject
private val imagesReviewerGroup = SharedTestDataADM.imagesReviewerGroup
implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance
@@ -68,30 +67,38 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"asked about all users" should {
"return a list if asked by SystemAdmin" in {
- responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = rootUser)
+ responderManager ! UsersGetRequestADM(
+ featureFactoryConfig = defaultFeatureFactoryConfig,
+ requestingUser = rootUser
+ )
val response = expectMsgType[UsersGetResponseADM](timeout)
response.users.nonEmpty should be(true)
response.users.size should be(18)
}
"return a list if asked by ProjectAdmin" in {
- responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = anythingAdminUser)
+ responderManager ! UsersGetRequestADM(
+ featureFactoryConfig = defaultFeatureFactoryConfig,
+ requestingUser = anythingAdminUser
+ )
val response = expectMsgType[UsersGetResponseADM](timeout)
response.users.nonEmpty should be(true)
response.users.size should be(18)
}
"return 'ForbiddenException' if asked by normal user'" in {
- responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = normalUser)
+ responderManager ! UsersGetRequestADM(
+ featureFactoryConfig = defaultFeatureFactoryConfig,
+ requestingUser = normalUser
+ )
expectMsg(timeout, Failure(ForbiddenException("ProjectAdmin or SystemAdmin permissions are required.")))
}
"not return the system and anonymous users" in {
- responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = rootUser)
+ responderManager ! UsersGetRequestADM(
+ featureFactoryConfig = defaultFeatureFactoryConfig,
+ requestingUser = rootUser
+ )
val response = expectMsgType[UsersGetResponseADM](timeout)
response.users.nonEmpty should be(true)
response.users.size should be(18)
@@ -233,15 +240,17 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"CREATE the user and return it's profile if the supplied email is unique " in {
responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "donald.duck",
- email = "donald.duck@example.com",
- givenName = "Donald",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
+ userCreatePayloadADM = UserCreatePayloadADM.create(
+ username = Username.create("donald.duck").fold(error => throw error, value => value),
+ email = Email
+ .create("donald.duck@example.com")
+ .fold(error => throw error, value => value),
+ givenName = GivenName.create("Donald").fold(error => throw error, value => value),
+ familyName = FamilyName.create("Duck").fold(error => throw error, value => value),
+ password = Password.create("test").fold(error => throw error, value => value),
+ status = Status.create(true).fold(error => throw error, value => value),
+ lang = LanguageCode.create("en").fold(error => throw error, value => value),
+ systemAdmin = SystemAdmin.create(false).fold(error => throw error, value => value)
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.anonymousUser,
@@ -258,15 +267,17 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'DuplicateValueException' if the supplied 'username' is not unique" in {
responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "root",
- email = "root2@example.com",
- givenName = "Donal",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
+ userCreatePayloadADM = UserCreatePayloadADM.create(
+ username = Username.create("root").fold(error => throw error, value => value),
+ email = Email
+ .create("root2@example.com")
+ .fold(error => throw error, value => value),
+ givenName = GivenName.create("Donald").fold(error => throw error, value => value),
+ familyName = FamilyName.create("Duck").fold(error => throw error, value => value),
+ password = Password.create("test").fold(error => throw error, value => value),
+ status = Status.create(true).fold(error => throw error, value => value),
+ lang = LanguageCode.create("en").fold(error => throw error, value => value),
+ systemAdmin = SystemAdmin.create(false).fold(error => throw error, value => value)
),
featureFactoryConfig = defaultFeatureFactoryConfig,
SharedTestDataADM.anonymousUser,
@@ -277,15 +288,17 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'DuplicateValueException' if the supplied 'email' is not unique" in {
responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "root2",
- email = "root@example.com",
- givenName = "Donal",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
+ userCreatePayloadADM = UserCreatePayloadADM.create(
+ username = Username.create("root2").fold(error => throw error, value => value),
+ email = Email
+ .create("root@example.com")
+ .fold(error => throw error, value => value),
+ givenName = GivenName.create("Donald").fold(error => throw error, value => value),
+ familyName = FamilyName.create("Duck").fold(error => throw error, value => value),
+ password = Password.create("test").fold(error => throw error, value => value),
+ status = Status.create(true).fold(error => throw error, value => value),
+ lang = LanguageCode.create("en").fold(error => throw error, value => value),
+ systemAdmin = SystemAdmin.create(false).fold(error => throw error, value => value)
),
featureFactoryConfig = defaultFeatureFactoryConfig,
SharedTestDataADM.anonymousUser,
@@ -293,64 +306,6 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
)
expectMsg(Failure(DuplicateValueException(s"User with the email 'root@example.com' already exists")))
}
-
- "return a 'BadRequestException' if the supplied 'username' contains invalid characters (@)" in {
- responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "donald.duck2@example.com",
- email = "donald.duck2@example.com",
- givenName = "Donal",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- SharedTestDataADM.anonymousUser,
- UUID.randomUUID
- )
- expectMsg(Failure(BadRequestException(s"The username 'donald.duck2@example.com' contains invalid characters")))
- }
-
- "return a 'BadRequestException' if the supplied 'username' contains invalid characters (-)" in {
- responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "donald-duck",
- email = "donald.duck2@example.com",
- givenName = "Donal",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- SharedTestDataADM.anonymousUser,
- UUID.randomUUID
- )
- expectMsg(Failure(BadRequestException(s"The username 'donald-duck' contains invalid characters")))
- }
-
- "return a 'BadRequestException' if the supplied 'email' is invalid" in {
- responderManager ! UserCreateRequestADM(
- createRequest = CreateUserApiRequestADM(
- username = "root3",
- email = "root3",
- givenName = "Donal",
- familyName = "Duck",
- password = "test",
- status = true,
- lang = "en",
- systemAdmin = false
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- SharedTestDataADM.anonymousUser,
- UUID.randomUUID
- )
- expectMsg(Failure(BadRequestException(s"The email 'root3' is invalid")))
- }
-
}
"asked to update a user" should {
@@ -358,137 +313,101 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"UPDATE the user's basic information" in {
/* User information is updated by the user */
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- email = None,
- givenName = Some("Donald"),
- familyName = None,
- lang = None
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
+ givenName = Some(GivenName.create("Donald").fold(error => throw error, value => value))
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.normalUser,
- UUID.randomUUID
+ apiRequestID = UUID.randomUUID
)
val response1 = expectMsgType[UserOperationResponseADM](timeout)
response1.user.givenName should equal("Donald")
/* User information is updated by a system admin */
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- email = None,
- givenName = None,
- familyName = Some("Duck"),
- lang = None
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
+ familyName = Some(FamilyName.create("Duck").fold(error => throw error, value => value))
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
- UUID.randomUUID
+ apiRequestID = UUID.randomUUID
)
val response2 = expectMsgType[UserOperationResponseADM](timeout)
response2.user.familyName should equal("Duck")
/* User information is updated by a system admin */
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- email = None,
- givenName = Some(SharedTestDataADM.normalUser.givenName),
- familyName = Some(SharedTestDataADM.normalUser.familyName),
- lang = None
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
+ givenName =
+ Some(GivenName.create(SharedTestDataADM.normalUser.givenName).fold(error => throw error, value => value)),
+ familyName = Some(
+ FamilyName.create(SharedTestDataADM.normalUser.familyName).fold(error => throw error, value => value)
+ )
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
- UUID.randomUUID
+ apiRequestID = UUID.randomUUID
)
val response3 = expectMsgType[UserOperationResponseADM](timeout)
response3.user.givenName should equal(SharedTestDataADM.normalUser.givenName)
response3.user.familyName should equal(SharedTestDataADM.normalUser.familyName)
-
}
"return a 'DuplicateValueException' if the supplied 'username' is not unique" in {
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ val duplicateUsername =
+ Some(Username.create(SharedTestDataADM.anythingUser1.username).fold(error => throw error, value => value))
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- username = Some("root")
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
+ username = duplicateUsername
),
featureFactoryConfig = defaultFeatureFactoryConfig,
SharedTestDataADM.superUser,
UUID.randomUUID
)
- expectMsg(Failure(DuplicateValueException(s"User with the username 'root' already exists")))
+ expectMsg(
+ Failure(
+ DuplicateValueException(
+ s"User with the username '${SharedTestDataADM.anythingUser1.username}' already exists"
+ )
+ )
+ )
}
"return a 'DuplicateValueException' if the supplied 'email' is not unique" in {
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ val duplicateEmail =
+ Some(Email.create(SharedTestDataADM.anythingUser1.email).fold(error => throw error, value => value))
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- email = Some("root@example.com")
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
+ email = duplicateEmail
),
featureFactoryConfig = defaultFeatureFactoryConfig,
SharedTestDataADM.superUser,
UUID.randomUUID
)
- expectMsg(Failure(DuplicateValueException(s"User with the email 'root@example.com' already exists")))
- }
-
- "return 'BadRequest' if the new 'username' contains invalid characters (@)" in {
-
- responderManager ! UserChangeBasicUserInformationRequestADM(
- userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- username = Some("donald.duck2@example.com")
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = SharedTestDataADM.superUser,
- UUID.randomUUID()
- )
-
- expectMsg(timeout,
- Failure(BadRequestException(s"The username 'donald.duck2@example.com' contains invalid characters")))
- }
-
- "return 'BadRequest' if the new 'username' contains invalid characters (-)" in {
-
- responderManager ! UserChangeBasicUserInformationRequestADM(
- userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- username = Some("donald-duck")
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = SharedTestDataADM.superUser,
- UUID.randomUUID()
- )
-
- expectMsg(timeout, Failure(BadRequestException(s"The username 'donald-duck' contains invalid characters")))
- }
-
- "return 'BadRequest' if the new 'email' is invalid" in {
-
- responderManager ! UserChangeBasicUserInformationRequestADM(
- userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- email = Some("root3")
- ),
- featureFactoryConfig = defaultFeatureFactoryConfig,
- requestingUser = SharedTestDataADM.superUser,
- UUID.randomUUID()
+ expectMsg(
+ Failure(
+ DuplicateValueException(s"User with the email '${SharedTestDataADM.anythingUser1.email}' already exists")
+ )
)
-
- expectMsg(timeout, Failure(BadRequestException(s"The email address 'root3' is invalid")))
}
"UPDATE the user's password (by himself)" in {
+ val requesterPassword = Password.create("test").fold(error => throw error, value => value)
+ val newPassword = Password.create("test123456").fold(error => throw error, value => value)
responderManager ! UserChangePasswordRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- requesterPassword = Some("test"), // of the requesting user
- newPassword = Some("test123456")
+ userUpdatePasswordPayload = UserUpdatePasswordPayloadADM(
+ requesterPassword = requesterPassword,
+ newPassword = newPassword
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.normalUser,
@@ -501,7 +420,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val resF = Authenticator.authenticateCredentialsV2(
credentials =
Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test123456")),
- featureFactoryConfig = defaultFeatureFactoryConfig,
+ featureFactoryConfig = defaultFeatureFactoryConfig
)(system, responderManager, executionContext)
resF map { res =>
@@ -510,11 +429,14 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
}
"UPDATE the user's password (by a system admin)" in {
+ val requesterPassword = Password.create("test").fold(error => throw error, value => value)
+ val newPassword = Password.create("test654321").fold(error => throw error, value => value)
+
responderManager ! UserChangePasswordRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- requesterPassword = Some("test"), // of the requesting user
- newPassword = Some("test654321")
+ userUpdatePasswordPayload = UserUpdatePasswordPayloadADM(
+ requesterPassword = requesterPassword,
+ newPassword = newPassword
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.rootUser,
@@ -527,7 +449,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val resF = Authenticator.authenticateCredentialsV2(
credentials =
Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test654321")),
- featureFactoryConfig = defaultFeatureFactoryConfig,
+ featureFactoryConfig = defaultFeatureFactoryConfig
)(system, responderManager, executionContext)
resF map { res =>
@@ -538,7 +460,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"UPDATE the user's status, (deleting) making him inactive " in {
responderManager ! UserChangeStatusRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(false)),
+ status = Status.create(false).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -549,7 +471,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
responderManager ! UserChangeStatusRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(true)),
+ status = Status.create(true).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -562,7 +484,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"UPDATE the user's system admin membership" in {
responderManager ! UserChangeSystemAdminMembershipStatusRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(true)),
+ systemAdmin = SystemAdmin.create(true).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -573,7 +495,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
responderManager ! UserChangeSystemAdminMembershipStatusRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(false)),
+ systemAdmin = SystemAdmin.create(false).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -586,11 +508,11 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'ForbiddenException' if the user requesting update is not the user itself or system admin" in {
/* User information is updated by other normal user */
- responderManager ! UserChangeBasicUserInformationRequestADM(
+ responderManager ! UserChangeBasicInformationRequestADM(
userIri = SharedTestDataADM.superUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
+ userUpdateBasicInformationPayload = UserUpdateBasicInformationPayloadADM(
email = None,
- givenName = Some("Donald"),
+ givenName = Some(GivenName.create("Donald").fold(error => throw error, value => value)),
familyName = None,
lang = None
),
@@ -601,14 +523,16 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
expectMsg(
timeout,
Failure(
- ForbiddenException("User information can only be changed by the user itself or a system administrator")))
+ ForbiddenException("User information can only be changed by the user itself or a system administrator")
+ )
+ )
/* Password is updated by other normal user */
responderManager ! UserChangePasswordRequestADM(
userIri = SharedTestDataADM.superUser.id,
- changeUserRequest = ChangeUserApiRequestADM(
- requesterPassword = Some("test"),
- newPassword = Some("test123456")
+ userUpdatePasswordPayload = UserUpdatePasswordPayloadADM(
+ requesterPassword = Password.create("test").fold(error => throw error, value => value),
+ newPassword = Password.create("test123456").fold(error => throw error, value => value)
),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.normalUser,
@@ -616,38 +540,43 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
)
expectMsg(
timeout,
- Failure(ForbiddenException("User's password can only be changed by the user itself or a system admin.")))
+ Failure(
+ ForbiddenException("User's password can only be changed by the user itself or a system administrator")
+ )
+ )
/* Status is updated by other normal user */
responderManager ! UserChangeStatusRequestADM(
userIri = SharedTestDataADM.superUser.id,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(false)),
+ status = Status.create(false).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.normalUser,
UUID.randomUUID
)
expectMsg(
timeout,
- Failure(ForbiddenException("User's status can only be changed by the user itself or a system administrator")))
+ Failure(ForbiddenException("User's status can only be changed by the user itself or a system administrator"))
+ )
/* System admin group membership */
responderManager ! UserChangeSystemAdminMembershipStatusRequestADM(
userIri = SharedTestDataADM.normalUser.id,
- changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(true)),
+ systemAdmin = SystemAdmin.create(true).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.normalUser,
UUID.randomUUID()
)
expectMsg(
timeout,
- Failure(ForbiddenException("User's system admin membership can only be changed by a system administrator")))
+ Failure(ForbiddenException("User's system admin membership can only be changed by a system administrator"))
+ )
}
"return 'BadRequest' if system user is requested to change" in {
responderManager ! UserChangeStatusRequestADM(
userIri = KnoraSystemInstances.Users.SystemUser.id,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(false)),
+ status = Status.create(false).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -660,7 +589,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
responderManager ! UserChangeStatusRequestADM(
userIri = KnoraSystemInstances.Users.AnonymousUser.id,
- changeUserRequest = ChangeUserApiRequestADM(status = Some(false)),
+ status = Status.create(false).fold(error => throw error, value => value),
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = SharedTestDataADM.superUser,
UUID.randomUUID()
@@ -668,18 +597,6 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
expectMsg(timeout, Failure(BadRequestException("Changes to built-in users are not allowed.")))
}
-
- "return 'BadRequest' if nothing would be changed during the update" in {
-
- an[BadRequestException] should be thrownBy ChangeUserApiRequestADM(None,
- None,
- None,
- None,
- None,
- None,
- None,
- None)
- }
}
"asked to update the user's project membership" should {
@@ -690,11 +607,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val membershipsBeforeUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.projects should equal(Seq())
- responderManager ! UserProjectMembershipAddRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectMembershipAddRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
val membershipUpdateResponse = expectMsgType[UserOperationResponseADM](timeout)
responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser)
@@ -717,11 +636,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val membershipsBeforeUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.projects should equal(Seq(imagesProject))
- responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
expectMsgType[UserOperationResponseADM](timeout)
responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser)
@@ -741,26 +662,34 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'ForbiddenException' if the user requesting update is not the project or system admin" in {
/* User is added to a project by a normal user */
- responderManager ! UserProjectMembershipAddRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
+ responderManager ! UserProjectMembershipAddRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
expectMsg(
timeout,
Failure(
- ForbiddenException("User's project membership can only be changed by a project or system administrator")))
+ ForbiddenException("User's project membership can only be changed by a project or system administrator")
+ )
+ )
/* User is removed from a project by a normal user */
- responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
+ responderManager ! UserProjectMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
expectMsg(
timeout,
Failure(
- ForbiddenException("User's project membership can only be changed by a project or system administrator")))
+ ForbiddenException("User's project membership can only be changed by a project or system administrator")
+ )
+ )
}
}
@@ -769,24 +698,30 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"ADD user to project admin group" in {
- responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipsGetRequestADM(
+ normalUser.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
val membershipsBeforeUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.projects should equal(Seq())
- responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipAddRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
expectMsgType[UserOperationResponseADM](timeout)
- responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipsGetRequestADM(
+ normalUser.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
val membershipsAfterUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout)
membershipsAfterUpdate.projects should equal(Seq(imagesProject))
@@ -801,24 +736,30 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
}
"DELETE user from project admin group" in {
- responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipsGetRequestADM(
+ normalUser.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
val membershipsBeforeUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.projects should equal(Seq(imagesProject))
- responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
expectMsgType[UserOperationResponseADM](timeout)
- responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserProjectAdminMembershipsGetRequestADM(
+ normalUser.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
val membershipsAfterUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout)
membershipsAfterUpdate.projects should equal(Seq())
@@ -835,26 +776,38 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'ForbiddenException' if the user requesting update is not the project or system admin" in {
/* User is added to a project by a normal user */
- responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
- expectMsg(timeout,
- Failure(
- ForbiddenException(
- "User's project admin membership can only be changed by a project or system administrator")))
+ responderManager ! UserProjectAdminMembershipAddRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
+ expectMsg(
+ timeout,
+ Failure(
+ ForbiddenException(
+ "User's project admin membership can only be changed by a project or system administrator"
+ )
+ )
+ )
/* User is removed from a project by a normal user */
- responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id,
- imagesProject.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
- expectMsg(timeout,
- Failure(
- ForbiddenException(
- "User's project admin membership can only be changed by a project or system administrator")))
+ responderManager ! UserProjectAdminMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesProject.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
+ expectMsg(
+ timeout,
+ Failure(
+ ForbiddenException(
+ "User's project admin membership can only be changed by a project or system administrator"
+ )
+ )
+ )
}
}
@@ -866,11 +819,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val membershipsBeforeUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.groups should equal(Seq())
- responderManager ! UserGroupMembershipAddRequestADM(normalUser.id,
- imagesReviewerGroup.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserGroupMembershipAddRequestADM(
+ normalUser.id,
+ imagesReviewerGroup.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
expectMsgType[UserOperationResponseADM](timeout)
responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser)
@@ -892,11 +847,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
val membershipsBeforeUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout)
membershipsBeforeUpdate.groups.map(_.id) should equal(Seq(imagesReviewerGroup.id))
- responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id,
- imagesReviewerGroup.id,
- defaultFeatureFactoryConfig,
- rootUser,
- UUID.randomUUID())
+ responderManager ! UserGroupMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesReviewerGroup.id,
+ defaultFeatureFactoryConfig,
+ rootUser,
+ UUID.randomUUID()
+ )
expectMsgType[UserOperationResponseADM](timeout)
responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser)
@@ -916,26 +873,34 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with
"return a 'ForbiddenException' if the user requesting update is not the project or system admin" in {
/* User is added to a project by a normal user */
- responderManager ! UserGroupMembershipAddRequestADM(normalUser.id,
- imagesReviewerGroup.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
+ responderManager ! UserGroupMembershipAddRequestADM(
+ normalUser.id,
+ imagesReviewerGroup.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
expectMsg(
timeout,
Failure(
- ForbiddenException("User's group membership can only be changed by a project or system administrator")))
+ ForbiddenException("User's group membership can only be changed by a project or system administrator")
+ )
+ )
/* User is removed from a project by a normal user */
- responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id,
- imagesReviewerGroup.id,
- defaultFeatureFactoryConfig,
- normalUser,
- UUID.randomUUID())
+ responderManager ! UserGroupMembershipRemoveRequestADM(
+ normalUser.id,
+ imagesReviewerGroup.id,
+ defaultFeatureFactoryConfig,
+ normalUser,
+ UUID.randomUUID()
+ )
expectMsg(
timeout,
Failure(
- ForbiddenException("User's group membership can only be changed by a project or system administrator")))
+ ForbiddenException("User's group membership can only be changed by a project or system administrator")
+ )
+ )
}
}