SEBSERV-13 #general implementation of entity activation service
This commit is contained in:
parent
70d66e6806
commit
41f9f25cd8
10 changed files with 373 additions and 156 deletions
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
|
@ -95,16 +93,4 @@ public final class UserFilter {
|
||||||
+ this.email + ", active=" + this.active + ", locale=" + this.locale + "]";
|
+ this.email + ", active=" + this.active + ", locale=" + this.locale + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserFilter ofActive() {
|
|
||||||
return new UserFilter(null, null, null, null, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserFilter ofInactive() {
|
|
||||||
return new UserFilter(null, null, null, null, false, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserFilter ofInstitution(@NotNull final Long institutionId) {
|
|
||||||
return new UserFilter(institutionId, null, null, null, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,6 @@ import java.util.Collections;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.validation.constraints.Email;
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
|
@ -25,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
|
import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
|
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||||
|
@ -36,7 +32,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||||
* to and from JSON within the Jackson library.
|
* to and from JSON within the Jackson library.
|
||||||
*
|
*
|
||||||
* This domain model is immutable and thread-save */
|
* This domain model is immutable and thread-save */
|
||||||
public final class UserInfo implements GrantEntity, Serializable {
|
public final class UserInfo implements GrantEntity, Activatable, Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 2526446136264377808L;
|
private static final long serialVersionUID = 2526446136264377808L;
|
||||||
|
|
||||||
|
@ -45,45 +41,34 @@ public final class UserInfo implements GrantEntity, Serializable {
|
||||||
public final String uuid;
|
public final String uuid;
|
||||||
|
|
||||||
/** The foreign key identifier to the institution where the User belongs to */
|
/** The foreign key identifier to the institution where the User belongs to */
|
||||||
@NotNull
|
|
||||||
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||||
public final Long institutionId;
|
public final Long institutionId;
|
||||||
|
|
||||||
/** Full name of the user */
|
/** Full name of the user */
|
||||||
@NotNull
|
|
||||||
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
|
||||||
@JsonProperty(USER.ATTR_NAME)
|
@JsonProperty(USER.ATTR_NAME)
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
/** The internal user name */
|
/** The internal user name */
|
||||||
@NotNull
|
|
||||||
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
|
||||||
@JsonProperty(USER.ATTR_USER_NAME)
|
@JsonProperty(USER.ATTR_USER_NAME)
|
||||||
public final String userName;
|
public final String userName;
|
||||||
|
|
||||||
/** E-mail address of the user */
|
/** E-mail address of the user */
|
||||||
@Email(message = "user:email:email:_:_:${validatedValue}")
|
|
||||||
@JsonProperty(USER.ATTR_EMAIL)
|
@JsonProperty(USER.ATTR_EMAIL)
|
||||||
public final String email;
|
public final String email;
|
||||||
|
|
||||||
/** Indicates whether this user is still active or not */
|
/** Indicates whether this user is still active or not */
|
||||||
@NotNull
|
|
||||||
@JsonProperty(USER.ATTR_ACTIVE)
|
@JsonProperty(USER.ATTR_ACTIVE)
|
||||||
public final Boolean active;
|
public final Boolean active;
|
||||||
|
|
||||||
/** The users locale */
|
/** The users locale */
|
||||||
@NotNull
|
|
||||||
@JsonProperty(USER.ATTR_LOCALE)
|
@JsonProperty(USER.ATTR_LOCALE)
|
||||||
public final Locale locale;
|
public final Locale locale;
|
||||||
|
|
||||||
/** The users time zone */
|
/** The users time zone */
|
||||||
@NotNull
|
|
||||||
@JsonProperty(USER.ATTR_TIMEZONE)
|
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||||
public final DateTimeZone timeZone;
|
public final DateTimeZone timeZone;
|
||||||
|
|
||||||
/** The users roles in a unmodifiable set. Is never null */
|
/** The users roles in a unmodifiable set. Is never null */
|
||||||
@NotNull
|
|
||||||
@NotEmpty(message = "user:roles:notEmpty:_:_:_")
|
|
||||||
@JsonProperty(USER_ROLE.REFERENCE_NAME)
|
@JsonProperty(USER_ROLE.REFERENCE_NAME)
|
||||||
public final Set<String> roles;
|
public final Set<String> roles;
|
||||||
|
|
||||||
|
@ -155,6 +140,12 @@ public final class UserInfo implements GrantEntity, Serializable {
|
||||||
return this.active;
|
return this.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.active;
|
||||||
|
}
|
||||||
|
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
return this.locale;
|
return this.locale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,23 +8,70 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
import javax.validation.constraints.Size;
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||||
|
|
||||||
public final class UserMod implements GrantEntity {
|
public final class UserMod implements GrantEntity {
|
||||||
|
|
||||||
public static final String ATTR_NAME_USER_INFO = "userInfo";
|
|
||||||
public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
|
public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
|
||||||
public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
|
public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
|
||||||
|
|
||||||
@JsonProperty(ATTR_NAME_USER_INFO)
|
public final String uuid;
|
||||||
private final UserInfo userInfo;
|
|
||||||
|
/** The foreign key identifier to the institution where the User belongs to */
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||||
|
public final Long institutionId;
|
||||||
|
|
||||||
|
/** Full name of the user */
|
||||||
|
@NotNull
|
||||||
|
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
||||||
|
@JsonProperty(USER.ATTR_NAME)
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
/** The internal user name */
|
||||||
|
@NotNull
|
||||||
|
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
||||||
|
@JsonProperty(USER.ATTR_USER_NAME)
|
||||||
|
public final String userName;
|
||||||
|
|
||||||
|
/** E-mail address of the user */
|
||||||
|
@Email(message = "user:email:email:_:_:${validatedValue}")
|
||||||
|
@JsonProperty(USER.ATTR_EMAIL)
|
||||||
|
public final String email;
|
||||||
|
|
||||||
|
/** The users locale */
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty(USER.ATTR_LOCALE)
|
||||||
|
public final Locale locale;
|
||||||
|
|
||||||
|
/** The users time zone */
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||||
|
public final DateTimeZone timeZone;
|
||||||
|
|
||||||
|
/** The users roles in a unmodifiable set. Is never null */
|
||||||
|
@NotNull
|
||||||
|
@NotEmpty(message = "user:roles:notEmpty:_:_:_")
|
||||||
|
@JsonProperty(USER_ROLE.REFERENCE_NAME)
|
||||||
|
public final Set<String> roles;
|
||||||
|
|
||||||
@Size(min = 8, max = 255, message = "user:password:size:{min}:{max}:${validatedValue}")
|
@Size(min = 8, max = 255, message = "user:password:size:{min}:{max}:${validatedValue}")
|
||||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD)
|
@JsonProperty(ATTR_NAME_NEW_PASSWORD)
|
||||||
|
@ -35,47 +82,97 @@ public final class UserMod implements GrantEntity {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public UserMod(
|
public UserMod(
|
||||||
@JsonProperty(ATTR_NAME_USER_INFO) final UserInfo userInfo,
|
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||||
|
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||||
|
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||||
|
@JsonProperty(USER.ATTR_USER_NAME) final String userName,
|
||||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
@JsonProperty(ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword) {
|
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword,
|
||||||
|
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||||
|
@JsonProperty(USER.ATTR_ACTIVE) final Boolean active,
|
||||||
|
@JsonProperty(USER.ATTR_LOCALE) final Locale locale,
|
||||||
|
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||||
|
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||||
|
|
||||||
this.userInfo = userInfo;
|
this.uuid = uuid;
|
||||||
|
this.institutionId = institutionId;
|
||||||
this.newPassword = newPassword;
|
this.newPassword = newPassword;
|
||||||
this.retypedNewPassword = retypedNewPassword;
|
this.retypedNewPassword = retypedNewPassword;
|
||||||
|
this.name = name;
|
||||||
|
this.userName = userName;
|
||||||
|
this.email = email;
|
||||||
|
this.locale = locale;
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
this.roles = (roles != null)
|
||||||
|
? Collections.unmodifiableSet(roles)
|
||||||
|
: Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserMod(final UserInfo userInfo, final String newPassword, final String retypedNewPassword) {
|
||||||
|
this.uuid = userInfo.uuid;
|
||||||
|
this.institutionId = userInfo.institutionId;
|
||||||
|
this.newPassword = newPassword;
|
||||||
|
this.retypedNewPassword = retypedNewPassword;
|
||||||
|
this.name = userInfo.name;
|
||||||
|
this.userName = userInfo.userName;
|
||||||
|
this.email = userInfo.email;
|
||||||
|
this.locale = userInfo.locale;
|
||||||
|
this.timeZone = userInfo.timeZone;
|
||||||
|
this.roles = userInfo.roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.userInfo.getId();
|
return this.uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public EntityType entityType() {
|
public EntityType entityType() {
|
||||||
return this.userInfo.entityType();
|
return EntityType.USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Long getInstitutionId() {
|
public Long getInstitutionId() {
|
||||||
return this.userInfo.getInstitutionId();
|
return this.institutionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String getOwnerUUID() {
|
public String getOwnerUUID() {
|
||||||
return this.userInfo.getOwnerUUID();
|
return this.uuid;
|
||||||
}
|
|
||||||
|
|
||||||
public UserInfo getUserInfo() {
|
|
||||||
return this.userInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNewPassword() {
|
public String getNewPassword() {
|
||||||
return this.newPassword;
|
return this.newPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return this.userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return this.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Locale getLocale() {
|
||||||
|
return this.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTimeZone getTimeZone() {
|
||||||
|
return this.timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getRoles() {
|
||||||
|
return this.roles;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRetypedNewPassword() {
|
public String getRetypedNewPassword() {
|
||||||
return this.retypedNewPassword;
|
return this.retypedNewPassword;
|
||||||
}
|
}
|
||||||
|
@ -88,37 +185,13 @@ public final class UserMod implements GrantEntity {
|
||||||
return passwordChangeRequest() && this.newPassword.equals(this.retypedNewPassword);
|
return passwordChangeRequest() && this.newPassword.equals(this.retypedNewPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean createNew() {
|
|
||||||
return this.userInfo.uuid == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ((this.userInfo == null) ? 0 : this.userInfo.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
final UserMod other = (UserMod) obj;
|
|
||||||
if (this.userInfo == null) {
|
|
||||||
if (other.userInfo != null)
|
|
||||||
return false;
|
|
||||||
} else if (!this.userInfo.equals(other.userInfo))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "UserMod [userInfo=" + this.userInfo + "]";
|
return "UserMod [uuid=" + this.uuid + ", institutionId=" + this.institutionId + ", name=" + this.name
|
||||||
|
+ ", userName="
|
||||||
|
+ this.userName + ", email=" + this.email + ", locale=" + this.locale + ", timeZone=" + this.timeZone
|
||||||
|
+ ", roles=" + this.roles
|
||||||
|
+ ", newPassword=" + this.newPassword + ", retypedNewPassword=" + this.retypedNewPassword + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.webservice.servicelayer.activation;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@WebServiceProfile
|
||||||
|
public class EntityActivationService {
|
||||||
|
|
||||||
|
private final Collection<ActivatableEntityDAO<?>> activatableEntityDAOs;
|
||||||
|
|
||||||
|
public EntityActivationService(final Collection<ActivatableEntityDAO<?>> activatableEntityDAOs) {
|
||||||
|
this.activatableEntityDAOs = activatableEntityDAOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(EntityActivationEvent.class)
|
||||||
|
public void notifyActivationEvent(final EntityActivationEvent event) {
|
||||||
|
for (final ActivatableEntityDAO<?> dao : this.activatableEntityDAOs) {
|
||||||
|
if (event.activated) {
|
||||||
|
dao.notifyActivation(event.entity);
|
||||||
|
} else {
|
||||||
|
dao.notifyDeactivation(event.entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser
|
||||||
/** The Data Access Object for all User related data like get user data within UserInfo,
|
/** The Data Access Object for all User related data like get user data within UserInfo,
|
||||||
* save and modify user related data within UserMod and get internal user principal data
|
* save and modify user related data within UserMod and get internal user principal data
|
||||||
* within SEBServerUser. */
|
* within SEBServerUser. */
|
||||||
public interface UserDAO extends EntityDAO<UserInfo> {
|
public interface UserDAO extends EntityDAO<UserInfo>, ActivatableEntityDAO<UserInfo> {
|
||||||
|
|
||||||
/** Use this to get UserInfo by database identifier
|
/** Use this to get UserInfo by database identifier
|
||||||
*
|
*
|
||||||
|
@ -48,11 +48,6 @@ public interface UserDAO extends EntityDAO<UserInfo> {
|
||||||
* @return a Result of SEBServerUser for specified username. Or an exception result on error case */
|
* @return a Result of SEBServerUser for specified username. Or an exception result on error case */
|
||||||
Result<SEBServerUser> sebServerUserByUsername(String username);
|
Result<SEBServerUser> sebServerUserByUsername(String username);
|
||||||
|
|
||||||
/** Use this to get a Collection of UserInfo for all active users.
|
|
||||||
*
|
|
||||||
* @return a Result of Collection of UserInfo for all active users. Or an exception result on error case */
|
|
||||||
Result<Collection<UserInfo>> allActive();
|
|
||||||
|
|
||||||
/** Use this to get a Collection of UserInfo that matches a given predicate.
|
/** Use this to get a Collection of UserInfo that matches a given predicate.
|
||||||
*
|
*
|
||||||
* NOTE: This first gets all UserRecord from database, for each creates new UserInfo
|
* NOTE: This first gets all UserRecord from database, for each creates new UserInfo
|
||||||
|
|
|
@ -13,12 +13,34 @@ import java.util.Collection;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
|
/** Interface for a DAo handling an Entity with relations to an user (account)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param <T> the concrete type of the Entity */
|
||||||
public interface UserRelatedEntityDAO<T extends Entity> extends EntityDAO<T> {
|
public interface UserRelatedEntityDAO<T extends Entity> extends EntityDAO<T> {
|
||||||
|
|
||||||
Result<Collection<T>> getAllForUser(String userId);
|
/** Get all Entity instances that has a relation to the user-account
|
||||||
|
* of a given user identity (UUID)
|
||||||
|
*
|
||||||
|
* @param userUuid the users identity
|
||||||
|
* @return A Result of all Entity instances that has a relation to the user-account
|
||||||
|
* of a given user identity (UUID) or a Result with error if happen */
|
||||||
|
Result<Collection<T>> getAllForUser(String userUuid);
|
||||||
|
|
||||||
Result<Integer> deleteUserReferences(final String userId);
|
/** Overwrite all user-references for entities that belongs to the user with the given identity
|
||||||
|
* to refer to an internal anonymous user-account
|
||||||
|
*
|
||||||
|
* @param userUuid the users identity
|
||||||
|
* @param deactivate indicates if the effected entities should also be deactivated if possible
|
||||||
|
* @return A Result with the number of overwrite Entity instances or with an error if happen */
|
||||||
|
Result<Integer> overwriteUserReferences(final String userUuid, boolean deactivate);
|
||||||
|
|
||||||
Result<Integer> deleteUserEnities(final String userId);
|
/** Delete all user-references for entities that belongs to the user with the given identity
|
||||||
|
*
|
||||||
|
* NOTE: This processes a hard-delete. All effected data will be lost.
|
||||||
|
*
|
||||||
|
* @param userUuid the users identity
|
||||||
|
* @return A Result with the number of deleted Entity instances or with an error if happen */
|
||||||
|
Result<Integer> deleteUserEnities(final String userUuid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Result<Collection<UserActivityLog>> getAllForUser(final String userId) {
|
public Result<Collection<UserActivityLog>> getAllForUser(final String userUuid) {
|
||||||
return all(userId, null, null, model -> true);
|
return all(userUuid, null, null, model -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,11 +182,11 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Result<Integer> deleteUserReferences(final String userId) {
|
public Result<Integer> overwriteUserReferences(final String userUuid, final boolean deactivate) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final List<UserActivityLogRecord> records = this.userLogRecordMapper.selectByExample()
|
final List<UserActivityLogRecord> records = this.userLogRecordMapper.selectByExample()
|
||||||
.where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualTo(userId))
|
.where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualTo(userUuid))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -196,19 +196,19 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
||||||
|
|
||||||
records
|
records
|
||||||
.stream()
|
.stream()
|
||||||
.forEach(this::overrrideUser);
|
.forEach(this::overwriteUser);
|
||||||
|
|
||||||
return Result.of(records.size());
|
return Result.of(records.size());
|
||||||
|
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
log.error(
|
log.error(
|
||||||
"Unexpected error while trying to delete all user references form activity logs for user with id: {}",
|
"Unexpected error while trying to delete all user references form activity logs for user with id: {}",
|
||||||
userId);
|
userUuid);
|
||||||
return Result.ofError(t);
|
return Result.ofError(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void overrrideUser(final UserActivityLogRecord record) {
|
private void overwriteUser(final UserActivityLogRecord record) {
|
||||||
final UserActivityLogRecord selective = new UserActivityLogRecord(
|
final UserActivityLogRecord selective = new UserActivityLogRecord(
|
||||||
record.getId(),
|
record.getId(),
|
||||||
this.userService.getAnonymousUser().getUsername(),
|
this.userService.getAnonymousUser().getUsername(),
|
||||||
|
@ -218,16 +218,16 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Integer> deleteUserEnities(final String userId) {
|
public Result<Integer> deleteUserEnities(final String userUuid) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return Result.of(this.userLogRecordMapper.deleteByExample()
|
return Result.of(this.userLogRecordMapper.deleteByExample()
|
||||||
.where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualToWhenPresent(userId))
|
.where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualToWhenPresent(userUuid))
|
||||||
.build()
|
.build()
|
||||||
.execute());
|
.execute());
|
||||||
|
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
log.error("Unexpected error while trying to delete all activity logs for user with id: {}", userId);
|
log.error("Unexpected error while trying to delete all activity logs for user with id: {}", userUuid);
|
||||||
return Result.ofError(t);
|
return Result.ofError(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,10 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException;
|
import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage.ErrorMessage;
|
import ch.ethz.seb.sebserver.gbl.model.APIMessage.ErrorMessage;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserFilter;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserFilter;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||||
|
@ -110,7 +110,7 @@ public class UserDaoImpl implements UserDAO {
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Result<Collection<UserInfo>> allActive() {
|
public Result<Collection<UserInfo>> allActive() {
|
||||||
return all(UserFilter.ofActive());
|
return all(new UserFilter(null, null, null, null, true, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,8 +168,7 @@ public class UserDaoImpl implements UserDAO {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final UserInfo userInfo = userMod.getUserInfo();
|
return (userMod.uuid != null)
|
||||||
return (userInfo.uuid != null)
|
|
||||||
? updateUser(userMod)
|
? updateUser(userMod)
|
||||||
: createNewUser(userMod);
|
: createNewUser(userMod);
|
||||||
|
|
||||||
|
@ -189,6 +188,63 @@ public class UserDaoImpl implements UserDAO {
|
||||||
return Result.ofError(new RuntimeException("TODO"));
|
return Result.ofError(new RuntimeException("TODO"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Result<UserInfo> setActive(final String entityId, final boolean active) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
this.userRecordMapper.updateByExampleSelective(
|
||||||
|
new UserRecord(
|
||||||
|
null, null, null, null, null, null, null, null, null,
|
||||||
|
BooleanUtils.toIntegerObject(active)))
|
||||||
|
.where(UserRecordDynamicSqlSupport.uuid, isEqualTo(entityId))
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
return byUuid(entityId);
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("unexpected error: ", e);
|
||||||
|
return Result.ofError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyActivation(final Entity source) {
|
||||||
|
// If an Institution has been deactivated, all its user accounts gets also be deactivated
|
||||||
|
if (source.entityType() == EntityType.INSTITUTION) {
|
||||||
|
setAllActiveForInstitution(Long.parseLong(source.getId()), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDeactivation(final Entity source) {
|
||||||
|
// If an Institution has been deactivated, all its user accounts gets also be deactivated
|
||||||
|
if (source.entityType() == EntityType.INSTITUTION) {
|
||||||
|
setAllActiveForInstitution(Long.parseLong(source.getId()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAllActiveForInstitution(final Long institutionId, final boolean active) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
final UserRecord record = new UserRecord(
|
||||||
|
null, null, null, null, null, null, null, null, null,
|
||||||
|
BooleanUtils.toIntegerObject(active));
|
||||||
|
|
||||||
|
this.userRecordMapper.updateByExampleSelective(record)
|
||||||
|
.where(UserRecordDynamicSqlSupport.institutionId, isEqualTo(institutionId))
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Unexpected error while trying to set all active: {} for institution: {}",
|
||||||
|
active,
|
||||||
|
institutionId,
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Result<Collection<UserInfo>> fromRecords(
|
private Result<Collection<UserInfo>> fromRecords(
|
||||||
final List<UserRecord> records,
|
final List<UserRecord> records,
|
||||||
final Predicate<UserInfo> predicate) {
|
final Predicate<UserInfo> predicate) {
|
||||||
|
@ -204,13 +260,8 @@ public class UserDaoImpl implements UserDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result<UserInfo> updateUser(final UserMod userMod) {
|
private Result<UserInfo> updateUser(final UserMod userMod) {
|
||||||
final UserInfo userInfo = userMod.getUserInfo();
|
return recordByUUID(userMod.uuid)
|
||||||
return recordByUUID(userInfo.uuid)
|
|
||||||
.flatMap(record -> {
|
.flatMap(record -> {
|
||||||
if (record.getInstitutionId().longValue() != userInfo.institutionId.longValue()) {
|
|
||||||
return Result.ofError(new IllegalArgumentException("The users institution cannot be changed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean changePWD = userMod.passwordChangeRequest();
|
final boolean changePWD = userMod.passwordChangeRequest();
|
||||||
if (changePWD && !userMod.newPasswordMatch()) {
|
if (changePWD && !userMod.newPasswordMatch()) {
|
||||||
return Result.ofError(new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH));
|
return Result.ofError(new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH));
|
||||||
|
@ -220,23 +271,22 @@ public class UserDaoImpl implements UserDAO {
|
||||||
record.getId(),
|
record.getId(),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
userInfo.name,
|
userMod.name,
|
||||||
userInfo.userName,
|
userMod.userName,
|
||||||
(changePWD) ? this.userPasswordEncoder.encode(userMod.getNewPassword()) : null,
|
(changePWD) ? this.userPasswordEncoder.encode(userMod.getNewPassword()) : null,
|
||||||
userInfo.email,
|
userMod.email,
|
||||||
userInfo.locale.toLanguageTag(),
|
userMod.locale.toLanguageTag(),
|
||||||
userInfo.timeZone.getID(),
|
userMod.timeZone.getID(),
|
||||||
BooleanUtils.toIntegerObject(userInfo.active));
|
null);
|
||||||
|
|
||||||
this.userRecordMapper.updateByPrimaryKeySelective(newRecord);
|
this.userRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||||
updateRolesForUser(record.getId(), userInfo.roles);
|
updateRolesForUser(record.getId(), userMod.roles);
|
||||||
|
|
||||||
return byId(record.getId());
|
return byId(record.getId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result<UserInfo> createNewUser(final UserMod userMod) {
|
private Result<UserInfo> createNewUser(final UserMod userMod) {
|
||||||
final UserInfo userInfo = userMod.getUserInfo();
|
|
||||||
|
|
||||||
if (!userMod.newPasswordMatch()) {
|
if (!userMod.newPasswordMatch()) {
|
||||||
return Result.ofError(new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH));
|
return Result.ofError(new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH));
|
||||||
|
@ -244,19 +294,19 @@ public class UserDaoImpl implements UserDAO {
|
||||||
|
|
||||||
final UserRecord newRecord = new UserRecord(
|
final UserRecord newRecord = new UserRecord(
|
||||||
null,
|
null,
|
||||||
userInfo.institutionId,
|
userMod.institutionId,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
userInfo.name,
|
userMod.name,
|
||||||
userInfo.userName,
|
userMod.userName,
|
||||||
this.userPasswordEncoder.encode(userMod.getNewPassword()),
|
this.userPasswordEncoder.encode(userMod.getNewPassword()),
|
||||||
userInfo.email,
|
userMod.email,
|
||||||
userInfo.locale.toLanguageTag(),
|
userMod.locale.toLanguageTag(),
|
||||||
userInfo.timeZone.getID(),
|
userMod.timeZone.getID(),
|
||||||
BooleanUtils.toIntegerObject(userInfo.active));
|
BooleanUtils.toInteger(false));
|
||||||
|
|
||||||
this.userRecordMapper.insert(newRecord);
|
this.userRecordMapper.insert(newRecord);
|
||||||
final Long newUserId = newRecord.getId();
|
final Long newUserId = newRecord.getId();
|
||||||
insertRolesForUser(newUserId, userInfo.roles);
|
insertRolesForUser(newUserId, userMod.roles);
|
||||||
return byId(newUserId);
|
return byId(newUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,4 +399,5 @@ public class UserDaoImpl implements UserDAO {
|
||||||
userInfo,
|
userInfo,
|
||||||
record.getPassword()));
|
record.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -16,11 +15,11 @@ import java.util.stream.Collectors;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||||
|
@ -29,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.activation.EntityActivationEvent;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
||||||
|
@ -64,19 +64,30 @@ public class UserAccountController {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET)
|
@RequestMapping(method = RequestMethod.GET)
|
||||||
public Collection<UserInfo> getAll(
|
public Collection<UserInfo> getAll(
|
||||||
//@RequestParam(required = false) final UserFilter filter,
|
@RequestParam(required = false) final Long institutionId,
|
||||||
@RequestBody(required = false) final UserFilter userFilter,
|
@RequestParam(required = false) final Boolean active,
|
||||||
final Principal principal) {
|
@RequestParam(required = false) final String name,
|
||||||
|
@RequestParam(required = false) final String userName,
|
||||||
|
@RequestParam(required = false) final String email,
|
||||||
|
@RequestParam(required = false) final String locale) {
|
||||||
|
|
||||||
// fist check if current user has any privileges for this action
|
// fist check if current user has any privileges for this action
|
||||||
this.authorizationGrantService.checkHasAnyPrivilege(
|
this.authorizationGrantService.checkHasAnyPrivilege(
|
||||||
EntityType.USER,
|
EntityType.USER,
|
||||||
PrivilegeType.READ_ONLY);
|
PrivilegeType.READ_ONLY);
|
||||||
|
|
||||||
|
final UserFilter userFilter = ((institutionId != null) ||
|
||||||
|
(active != null) ||
|
||||||
|
(name != null) ||
|
||||||
|
(userName != null) ||
|
||||||
|
(email != null) ||
|
||||||
|
(locale != null))
|
||||||
|
? new UserFilter(institutionId, name, userName, email, active, locale)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (this.authorizationGrantService.hasBasePrivilege(
|
if (this.authorizationGrantService.hasBasePrivilege(
|
||||||
EntityType.USER,
|
EntityType.USER,
|
||||||
PrivilegeType.READ_ONLY,
|
PrivilegeType.READ_ONLY)) {
|
||||||
principal)) {
|
|
||||||
|
|
||||||
return (userFilter != null)
|
return (userFilter != null)
|
||||||
? this.userDao.all(userFilter).getOrThrow()
|
? this.userDao.all(userFilter).getOrThrow()
|
||||||
|
@ -86,8 +97,7 @@ public class UserAccountController {
|
||||||
|
|
||||||
final Predicate<UserInfo> grantFilter = this.authorizationGrantService.getGrantFilter(
|
final Predicate<UserInfo> grantFilter = this.authorizationGrantService.getGrantFilter(
|
||||||
EntityType.USER,
|
EntityType.USER,
|
||||||
PrivilegeType.READ_ONLY,
|
PrivilegeType.READ_ONLY);
|
||||||
principal);
|
|
||||||
|
|
||||||
if (userFilter == null) {
|
if (userFilter == null) {
|
||||||
|
|
||||||
|
@ -108,14 +118,14 @@ public class UserAccountController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/me", method = RequestMethod.GET)
|
@RequestMapping(value = "/me", method = RequestMethod.GET)
|
||||||
public UserInfo loggedInUser(final Authentication auth) {
|
public UserInfo loggedInUser() {
|
||||||
return this.userService
|
return this.userService
|
||||||
.getCurrentUser()
|
.getCurrentUser()
|
||||||
.getUserInfo();
|
.getUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/{userUUID}", method = RequestMethod.GET)
|
@RequestMapping(value = "/{userUUID}", method = RequestMethod.GET)
|
||||||
public UserInfo accountInfo(@PathVariable final String userUUID, final Principal principal) {
|
public UserInfo accountInfo(@PathVariable final String userUUID) {
|
||||||
return this.userDao
|
return this.userDao
|
||||||
.byUuid(userUUID)
|
.byUuid(userUUID)
|
||||||
.flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
|
.flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
|
||||||
|
@ -126,27 +136,42 @@ public class UserAccountController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/create", method = RequestMethod.PUT)
|
@RequestMapping(value = "/create", method = RequestMethod.PUT)
|
||||||
public UserInfo createUser(
|
public UserInfo createUser(@Valid @RequestBody final UserMod userData) {
|
||||||
@Valid @RequestBody final UserMod userData,
|
|
||||||
final Principal principal) {
|
|
||||||
|
|
||||||
return _saveUser(userData, PrivilegeType.WRITE)
|
return _saveUser(userData, PrivilegeType.WRITE)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/save", method = RequestMethod.POST)
|
@RequestMapping(value = "/save", method = RequestMethod.POST)
|
||||||
public UserInfo saveUser(
|
public UserInfo saveUser(@Valid @RequestBody final UserMod userData) {
|
||||||
@Valid @RequestBody final UserMod userData,
|
|
||||||
final Principal principal) {
|
|
||||||
|
|
||||||
return _saveUser(userData, PrivilegeType.MODIFY)
|
return _saveUser(userData, PrivilegeType.MODIFY)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/{userUUID}/activate", method = RequestMethod.POST)
|
||||||
|
public UserInfo activateUser(@PathVariable final String userUUID) {
|
||||||
|
return setActivity(userUUID, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/{userUUID}/deactivate", method = RequestMethod.POST)
|
||||||
|
public UserInfo deactivateUser(@PathVariable final String userUUID) {
|
||||||
|
return setActivity(userUUID, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo setActivity(final String userUUID, final boolean activity) {
|
||||||
|
return this.userDao.byUuid(userUUID)
|
||||||
|
.flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(userInfo, PrivilegeType.WRITE))
|
||||||
|
.flatMap(userInfo -> this.userDao.setActive(userInfo.uuid, activity))
|
||||||
|
.map(userInfo -> {
|
||||||
|
this.applicationEventPublisher.publishEvent(new EntityActivationEvent(userInfo, activity));
|
||||||
|
return userInfo;
|
||||||
|
})
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
private Result<UserInfo> _saveUser(final UserMod userData, final PrivilegeType privilegeType) {
|
private Result<UserInfo> _saveUser(final UserMod userData, final PrivilegeType privilegeType) {
|
||||||
|
|
||||||
final ActivityType actionType = (userData.getUserInfo().uuid == null)
|
final ActivityType actionType = (userData.uuid == null)
|
||||||
? ActivityType.CREATE
|
? ActivityType.CREATE
|
||||||
: ActivityType.MODIFY;
|
: ActivityType.MODIFY;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.model.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserFilter;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
@ -152,15 +151,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllUserInfoWithSearchInactive() throws Exception {
|
public void getAllUserInfoWithSearchInactive() throws Exception {
|
||||||
final UserFilter filter = UserFilter.ofInactive();
|
|
||||||
final String filterJson = this.jsonMapper.writeValueAsString(filter);
|
|
||||||
|
|
||||||
final String token = getSebAdminAccess();
|
final String token = getSebAdminAccess();
|
||||||
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||||
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT)
|
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false")
|
||||||
.header("Authorization", "Bearer " + token)
|
.header("Authorization", "Bearer " + token))
|
||||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
|
||||||
.content(filterJson))
|
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andReturn().getResponse().getContentAsString(),
|
.andReturn().getResponse().getContentAsString(),
|
||||||
new TypeReference<List<UserInfo>>() {
|
new TypeReference<List<UserInfo>>() {
|
||||||
|
@ -173,15 +167,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllUserInfoWithSearchUsernameLike() throws Exception {
|
public void getAllUserInfoWithSearchUsernameLike() throws Exception {
|
||||||
final UserFilter filter = new UserFilter(null, null, "exam", null, null, null);
|
|
||||||
final String filterJson = this.jsonMapper.writeValueAsString(filter);
|
|
||||||
|
|
||||||
final String token = getSebAdminAccess();
|
final String token = getSebAdminAccess();
|
||||||
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||||
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT)
|
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?userName=exam")
|
||||||
.header("Authorization", "Bearer " + token)
|
.header("Authorization", "Bearer " + token))
|
||||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
|
||||||
.content(filterJson))
|
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andReturn().getResponse().getContentAsString(),
|
.andReturn().getResponse().getContentAsString(),
|
||||||
new TypeReference<List<UserInfo>>() {
|
new TypeReference<List<UserInfo>>() {
|
||||||
|
@ -236,6 +225,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
||||||
|
|
||||||
assertNotNull(createdUserGet);
|
assertNotNull(createdUserGet);
|
||||||
assertEquals(createdUser, createdUserGet);
|
assertEquals(createdUser, createdUserGet);
|
||||||
|
assertFalse(createdUserGet.isActive());
|
||||||
|
|
||||||
// check user activity log for newly created user
|
// check user activity log for newly created user
|
||||||
final List<UserActivityLog> logs = this.jsonMapper.readValue(
|
final List<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||||
|
@ -497,6 +487,50 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
||||||
assertEquals("1300", messages.get(0).messageCode);
|
assertEquals("1300", messages.get(0).messageCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deactivateUserAccount() throws Exception {
|
||||||
|
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||||
|
final String examAdminToken = getExamAdmin1();
|
||||||
|
this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/deactivate")
|
||||||
|
.header("Authorization", "Bearer " + examAdminToken))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// With SEB Administrator it should work
|
||||||
|
final String sebAdminToken = getSebAdminAccess();
|
||||||
|
final UserInfo deactivatedUser = this.jsonMapper.readValue(
|
||||||
|
this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/deactivate")
|
||||||
|
.header("Authorization", "Bearer " + sebAdminToken))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andReturn().getResponse().getContentAsString(),
|
||||||
|
new TypeReference<UserInfo>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
assertNotNull(deactivatedUser);
|
||||||
|
assertFalse(deactivatedUser.isActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void activateUserAccount() throws Exception {
|
||||||
|
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||||
|
final String examAdminToken = getExamAdmin1();
|
||||||
|
this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/activate")
|
||||||
|
.header("Authorization", "Bearer " + examAdminToken))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
// With SEB Administrator it should work
|
||||||
|
final String sebAdminToken = getSebAdminAccess();
|
||||||
|
final UserInfo deactivatedUser = this.jsonMapper.readValue(
|
||||||
|
this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/activate")
|
||||||
|
.header("Authorization", "Bearer " + sebAdminToken))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andReturn().getResponse().getContentAsString(),
|
||||||
|
new TypeReference<UserInfo>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
assertNotNull(deactivatedUser);
|
||||||
|
assertTrue(deactivatedUser.isActive());
|
||||||
|
}
|
||||||
|
|
||||||
private UserInfo getUserInfo(final String name, final Collection<UserInfo> infos) {
|
private UserInfo getUserInfo(final String name, final Collection<UserInfo> infos) {
|
||||||
return infos
|
return infos
|
||||||
.stream()
|
.stream()
|
||||||
|
|
Loading…
Reference in a new issue