created controller abstraction for Entity and ActivatableEntity

This commit is contained in:
anhefti 2019-01-20 16:28:55 +01:00
parent 2f8b796b86
commit ca20785400
39 changed files with 1376 additions and 572 deletions

View file

@ -10,6 +10,9 @@ package ch.ethz.seb.sebserver.gbl.model;
public interface Entity extends ModelIdAware {
public static final String ATTR_ID = "id";
public static final String ATTR_INSTITUTION = "institution";
EntityType entityType();
String getName();

View file

@ -8,35 +8,40 @@
package ch.ethz.seb.sebserver.gbl.model;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
public class EntityKey {
public final String entityId;
@JsonProperty(value = "modelId", required = true)
public final String modelId;
@JsonProperty(value = "entityType", required = true)
public final EntityType entityType;
@JsonIgnore
public final boolean isIdPK;
@JsonCreator
public EntityKey(
@NotNull final Long entityId,
@NotNull final EntityType entityType) {
@JsonProperty(value = "modelId", required = true) final String modelId,
@JsonProperty(value = "entityType", required = true) final EntityType entityType) {
this.entityId = String.valueOf(entityId);
this.modelId = modelId;
this.entityType = entityType;
this.isIdPK = entityType != EntityType.USER;
}
public EntityKey(
final Long pk,
final EntityType entityType) {
this.modelId = String.valueOf(pk);
this.entityType = entityType;
this.isIdPK = true;
}
public EntityKey(
@NotNull final String entityId,
@NotNull final EntityType entityType,
final boolean isIdPK) {
this.entityId = entityId;
this.entityType = entityType;
this.isIdPK = isIdPK;
}
public String getEntityId() {
return this.entityId;
public String getModelId() {
return this.modelId;
}
public EntityType getEntityType() {
@ -47,8 +52,8 @@ public class EntityKey {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.entityId == null) ? 0 : this.entityId.hashCode());
result = prime * result + ((this.entityType == null) ? 0 : this.entityType.hashCode());
result = prime * result + ((this.modelId == null) ? 0 : this.modelId.hashCode());
return result;
}
@ -61,19 +66,19 @@ public class EntityKey {
if (getClass() != obj.getClass())
return false;
final EntityKey other = (EntityKey) obj;
if (this.entityId == null) {
if (other.entityId != null)
return false;
} else if (!this.entityId.equals(other.entityId))
return false;
if (this.entityType != other.entityType)
return false;
if (this.modelId == null) {
if (other.modelId != null)
return false;
} else if (!this.modelId.equals(other.modelId))
return false;
return true;
}
@Override
public String toString() {
return "EntityKey [entityId=" + this.entityId + ", entityType=" + this.entityType + "]";
return "EntityKey [modelId=" + this.modelId + ", entityType=" + this.entityType + "]";
}
}

View file

@ -19,7 +19,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
@JsonProperty(value = "entityType", required = true)
public final EntityType entityType;
@JsonProperty(value = Domain.ATTR_ID, required = true)
public final String id;
public final String modelId;
@JsonProperty(value = "name", required = true)
public final String name;
@ -30,14 +30,14 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
@JsonProperty(value = "name", required = true) final String name) {
this.entityType = entityType;
this.id = id;
this.modelId = id;
this.name = name;
}
public EntityKeyAndName(final EntityKey entityKey, final String name) {
this.entityType = entityKey.entityType;
this.id = entityKey.entityId;
this.modelId = entityKey.modelId;
this.name = name;
}
@ -45,10 +45,6 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
return this.entityType;
}
public String getId() {
return this.id;
}
@Override
public String getName() {
return this.name;
@ -57,7 +53,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
@Override
@JsonIgnore
public String getModelId() {
return this.id;
return this.modelId;
}
@Override
@ -65,7 +61,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
final int prime = 31;
int result = 1;
result = prime * result + ((this.entityType == null) ? 0 : this.entityType.hashCode());
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
result = prime * result + ((this.modelId == null) ? 0 : this.modelId.hashCode());
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@ -81,10 +77,10 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
final EntityKeyAndName other = (EntityKeyAndName) obj;
if (this.entityType != other.entityType)
return false;
if (this.id == null) {
if (other.id != null)
if (this.modelId == null) {
if (other.modelId != null)
return false;
} else if (!this.id.equals(other.id))
} else if (!this.modelId.equals(other.modelId))
return false;
if (this.name == null) {
if (other.name != null)
@ -96,7 +92,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
@Override
public String toString() {
return "EntityIdAndName [entityType=" + this.entityType + ", id=" + this.id + ", name=" + this.name + "]";
return "EntityIdAndName [entityType=" + this.entityType + ", id=" + this.modelId + ", name=" + this.name + "]";
}
}

View file

@ -9,30 +9,46 @@
package ch.ethz.seb.sebserver.gbl.model;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public class EntityProcessingReport {
@JsonProperty(value = "source", required = true)
public final Collection<Entity> source;
public final Collection<EntityKey> source;
@JsonProperty(value = "dependencies", required = true)
public final Collection<EntityKeyAndName> dependencies;
public final Collection<EntityKey> dependencies;
@JsonProperty(value = "errors", required = true)
public final Map<EntityKeyAndName, String> errors;
public final Collection<ErrorEntry> errors;
@JsonCreator
public EntityProcessingReport(
@JsonProperty(value = "source", required = true) final Collection<Entity> source,
@JsonProperty(value = "dependencies", required = true) final Collection<EntityKeyAndName> dependencies,
@JsonProperty(value = "errors", required = true) final Map<EntityKeyAndName, String> errors) {
@JsonProperty(value = "source", required = true) final Collection<EntityKey> source,
@JsonProperty(value = "dependencies", required = true) final Collection<EntityKey> dependencies,
@JsonProperty(value = "errors", required = true) final Collection<ErrorEntry> errors) {
this.source = Utils.immutableCollectionOf(source);
this.dependencies = Utils.immutableCollectionOf(dependencies);
this.errors = Utils.immutableCollectionOf(errors);
}
public static final class ErrorEntry {
public final EntityKey entityKey;
public final APIMessage errorMessage;
@JsonCreator
public ErrorEntry(
@JsonProperty(value = "entity_key", required = true) final EntityKey entityKey,
@JsonProperty(value = "error_message", required = true) final APIMessage errorMessage) {
this.entityKey = entityKey;
this.errorMessage = errorMessage;
}
this.source = Collections.unmodifiableCollection(source);
this.dependencies = Collections.unmodifiableCollection(dependencies);
this.errors = Collections.unmodifiableMap(errors);
}
}

View file

@ -22,11 +22,11 @@ public final class Page<T> {
DESCENDING
}
public static final String ATTR_NUMBER_OF_PAGES = "numberOfPages";
public static final String ATTR_PAGE_NUMBER = "pageNumber";
public static final String ATTR_PAGE_SIZE = "pageSize";
public static final String ATTR_SORT_BY = "sortBy";
public static final String ATTR_SORT_ORDER = "sortOrder";
public static final String ATTR_NUMBER_OF_PAGES = "number_of_pages";
public static final String ATTR_PAGE_NUMBER = "page_number";
public static final String ATTR_PAGE_SIZE = "page_size";
public static final String ATTR_SORT_BY = "sort_by";
public static final String ATTR_SORT_ORDER = "sort_order";
public static final String ATTR_CONTENT = "content";
@JsonProperty(ATTR_NUMBER_OF_PAGES)

View file

@ -26,7 +26,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
public final class Exam implements GrantEntity, Activatable {
public static final String FILTER_ATTR_INSTITUTION = "institution";
public static final String FILTER_ATTR_INSTITUTION = ATTR_INSTITUTION;
public static final String FILTER_ATTR_LMS_SETUP = "lms_setup";
public static final String FILTER_ATTR_NAME = "name_like";
public static final String FILTER_ATTR_STATUS = "status";

View file

@ -22,11 +22,6 @@ public final class QuizData {
public static final String FILTER_ATTR_NAME = "name_like";
public static final String FILTER_ATTR_START_TIME = "start_timestamp";
public static final String PAGE_ATTR_NUMBER = "page_number";
public static final String PAGE_ATTR_SIZE = "page_size";
public static final String PAGE_ATTR_SORT_BY = "sort_by";
public static final String PAGE_ATTR_SORT_ORDER = "sort_order";
public static final String QUIZ_ATTR_ID = "quiz_id";
public static final String QUIZ_ATTR_NAME = "quiz_name";
public static final String QUIZ_ATTR_DESCRIPTION = "quiz_description";

View file

@ -19,6 +19,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.Acti
public class UserActivityLog implements Entity {
public static final String FILTER_ATTR_INSTITUTION = ATTR_INSTITUTION;
public static final String FILTER_ATTR_FROM = "from";
public static final String FILTER_ATTR_TO = "to";
public static final String FILTER_ATTR_ACTIVITY_TYPES = "activity_types";
public static final String FILTER_ATTR_ENTITY_TYPES = "entity_types";
@JsonIgnore
public final Long id;
@JsonProperty(USER_ACTIVITY_LOG.ATTR_USER_UUID)

View file

@ -18,6 +18,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import ch.ethz.seb.sebserver.gbl.Constants;
@ -105,4 +106,24 @@ public final class Utils {
return map;
}
public static DateTime toDateTime(final String dateString) {
if (StringUtils.isBlank(dateString)) {
return null;
}
if (dateString.contains(".")) {
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_MILLIS);
} else {
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
}
}
public static Long toMilliSeconds(final String dateString) {
if (StringUtils.isBlank(dateString)) {
return null;
}
return toDateTime(dateString).getMillis();
}
}

View file

@ -25,6 +25,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
@ -50,6 +51,25 @@ public class PaginationService {
initSortColumnMapping();
}
/** Use this to verify whether native sorting (on SQL level) is supported for a given orderBy column
* and a given SqlTable or not.
*
* @param table SqlTable the SQL table (MyBatis)
* @param orderBy the orderBy columnName
* @return true if there is native sorting support for the given attributes */
public boolean isNativeSortingSupported(final SqlTable table, final String orderBy) {
if (StringUtils.isBlank(orderBy)) {
return false;
}
final Map<String, String> tableMap = this.sortColumnMapping.get(table.name());
if (tableMap == null) {
return false;
}
return tableMap.containsKey(orderBy);
}
public void setDefaultLimitOfNotSet(final SqlTable table) {
if (PageHelper.getLocalPage() != null) {
return;
@ -69,6 +89,20 @@ public class PaginationService {
setPagination(1, this.maxPageSize, sortBy, sortOrder, table);
}
public int getPageNumber(final Integer pageNumber) {
return (pageNumber == null)
? 1
: pageNumber;
}
public int getPageSize(final Integer pageSize) {
return (pageSize == null || pageSize < 0)
? this.defaultPageSize
: (pageSize > this.maxPageSize)
? this.maxPageSize
: pageSize;
}
public com.github.pagehelper.Page<Object> setPagination(
final Integer pageNumber,
final Integer pageSize,
@ -76,18 +110,8 @@ public class PaginationService {
final Page.SortOrder sortOrder,
final SqlTable table) {
final int _pageNumber = (pageNumber == null)
? 1
: pageNumber;
final int _pageSize = (pageSize == null || pageSize < 0)
? this.defaultPageSize
: (pageSize > this.maxPageSize)
? this.maxPageSize
: pageSize;
final com.github.pagehelper.Page<Object> startPage =
PageHelper.startPage(_pageNumber, _pageSize, true, true, false);
PageHelper.startPage(getPageNumber(pageNumber), getPageSize(pageSize), true, true, false);
final String sortColumnName = verifySortColumnName(sortBy, table);
if (StringUtils.isNoneBlank(sortColumnName)) {
@ -111,7 +135,7 @@ public class PaginationService {
final com.github.pagehelper.Page<Object> page = setPagination(pageNumber, pageSize, sortBy, sortOrder, table);
final Collection<T> pageList = delegate.get();
return new Page<>(page.getPages(), pageNumber, sortBy, sortOrder, pageList);
return new Page<>(page.getPages(), page.getPageNum(), sortBy, sortOrder, pageList);
}
private String verifySortColumnName(final String sortBy, final SqlTable table) {
@ -130,6 +154,7 @@ public class PaginationService {
// TODO is it possible to generate this within MyBatis generator?
private void initSortColumnMapping() {
// User Table
final Map<String, String> userTableMap = new HashMap<>();
userTableMap.put(Domain.USER.ATTR_NAME, UserRecordDynamicSqlSupport.name.name());
@ -163,6 +188,21 @@ public class PaginationService {
UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.name(),
Domain.USER_ACTIVITY_LOG.ATTR_ID);
// Exam Table
final Map<String, String> examTableMap = new HashMap<>();
examTableMap.put(
Domain.EXAM.ATTR_INSTITUTION_ID,
ExamRecordDynamicSqlSupport.institutionId.name());
examTableMap.put(
Domain.EXAM.ATTR_LMS_SETUP_ID,
ExamRecordDynamicSqlSupport.lmsSetupId.name());
examTableMap.put(
Domain.EXAM.ATTR_TYPE,
ExamRecordDynamicSqlSupport.type.name());
examTableMap.put(
Domain.EXAM.ATTR_STATUS,
ExamRecordDynamicSqlSupport.status.name());
}
}

View file

@ -22,7 +22,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
public interface AuthorizationGrantService {
/** Gets the UserService that is bundled within the AuthorizationGrantService
*
*
* @return the UserService that is bundled within the AuthorizationGrantService */
UserService getUserService();
@ -33,6 +33,10 @@ public interface AuthorizationGrantService {
* @param privilegeType the PrivilegeType to check on EntityType */
void checkHasAnyPrivilege(EntityType entityType, PrivilegeType privilegeType);
void checkPrivilege(EntityType entityType, PrivilegeType privilegeType, Long institutionId);
void checkPrivilege(EntityType entityType, PrivilegeType privilegeType, Long institutionId, Long ownerId);
/** Check if current user has grant on a given GrantEntity instance for specified PrivilegeType
*
* @param entity The GrantEntity to check specified PrivilegeType for

View file

@ -120,49 +120,86 @@ public class AuthorizationGrantServiceImpl implements AuthorizationGrantService
}
@Override
public void checkHasAnyPrivilege(final EntityType entityType, final PrivilegeType grantType) {
public void checkHasAnyPrivilege(final EntityType entityType, final PrivilegeType privilegeType) {
final SEBServerUser currentUser = this.userService.getCurrentUser();
if (hasBasePrivilege(entityType, grantType, currentUser) ||
hasInstitutionalPrivilege(entityType, grantType, currentUser)) {
if (hasBasePrivilege(entityType, privilegeType, currentUser) ||
hasInstitutionalPrivilege(entityType, privilegeType, currentUser)) {
return;
}
throw new PermissionDeniedException(entityType, grantType, currentUser.getUserInfo().uuid);
throw new PermissionDeniedException(entityType, privilegeType, currentUser.getUserInfo().uuid);
}
@Override
public <E extends GrantEntity> Result<E> checkGrantOnEntity(final E entity, final PrivilegeType grantType) {
public void checkPrivilege(
final EntityType entityType,
final PrivilegeType privilegeType,
final Long institutionId) {
final SEBServerUser currentUser = this.userService.getCurrentUser();
if (hasGrant(entity, grantType, currentUser)) {
if (hasBasePrivilege(entityType, privilegeType, currentUser)) {
return;
}
if (institutionId == null) {
throw new PermissionDeniedException(entityType, privilegeType, currentUser.getUserInfo().uuid);
}
if (hasInstitutionalPrivilege(entityType, privilegeType, currentUser) &&
currentUser.institutionId().longValue() == institutionId.longValue()) {
return;
}
throw new PermissionDeniedException(entityType, privilegeType, currentUser.getUserInfo().uuid);
}
@Override
public void checkPrivilege(
final EntityType entityType,
final PrivilegeType privilegeType,
final Long institutionId,
final Long ownerId) {
final SEBServerUser currentUser = this.userService.getCurrentUser();
// TODO Auto-generated method stub
throw new PermissionDeniedException(entityType, privilegeType, currentUser.getUserInfo().uuid);
}
@Override
public <E extends GrantEntity> Result<E> checkGrantOnEntity(final E entity, final PrivilegeType privilegeType) {
final SEBServerUser currentUser = this.userService.getCurrentUser();
if (hasGrant(entity, privilegeType, currentUser)) {
return Result.of(entity);
} else {
return Result.ofError(new PermissionDeniedException(entity, grantType, currentUser.getUserInfo().uuid));
return Result.ofError(new PermissionDeniedException(entity, privilegeType, currentUser.getUserInfo().uuid));
}
}
@Override
public boolean hasBasePrivilege(final EntityType entityType, final PrivilegeType grantType) {
return hasBasePrivilege(entityType, grantType, this.userService.getCurrentUser());
public boolean hasBasePrivilege(final EntityType entityType, final PrivilegeType privilegeType) {
return hasBasePrivilege(entityType, privilegeType, this.userService.getCurrentUser());
}
@Override
public boolean hasBasePrivilege(
final EntityType entityType,
final PrivilegeType grantType,
final PrivilegeType privilegeType,
final Principal principal) {
return hasBasePrivilege(entityType, grantType, this.userService.extractFromPrincipal(principal));
return hasBasePrivilege(entityType, privilegeType, this.userService.extractFromPrincipal(principal));
}
private boolean hasBasePrivilege(
final EntityType entityType,
final PrivilegeType grantType,
final PrivilegeType privilegeType,
final SEBServerUser user) {
for (final UserRole role : user.getUserRoles()) {
final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role));
if (roleTypeGrant != null && roleTypeGrant.hasBasePrivilege(grantType)) {
if (roleTypeGrant != null && roleTypeGrant.hasBasePrivilege(privilegeType)) {
return true;
}
}
@ -171,27 +208,36 @@ public class AuthorizationGrantServiceImpl implements AuthorizationGrantService
}
@Override
public boolean hasInstitutionalPrivilege(final EntityType entityType, final PrivilegeType grantType) {
return hasInstitutionalPrivilege(entityType, grantType, this.userService.getCurrentUser());
public boolean hasInstitutionalPrivilege(
final EntityType entityType,
final PrivilegeType privilegeType) {
return hasInstitutionalPrivilege(
entityType,
privilegeType,
this.userService.getCurrentUser());
}
@Override
public boolean hasInstitutionalPrivilege(
final EntityType entityType,
final PrivilegeType grantType,
final PrivilegeType privilegeType,
final Principal principal) {
return hasInstitutionalPrivilege(entityType, grantType, this.userService.extractFromPrincipal(principal));
return hasInstitutionalPrivilege(
entityType,
privilegeType,
this.userService.extractFromPrincipal(principal));
}
private boolean hasInstitutionalPrivilege(
final EntityType entityType,
final PrivilegeType grantType,
final PrivilegeType privilegeType,
final SEBServerUser user) {
for (final UserRole role : user.getUserRoles()) {
final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role));
if (roleTypeGrant != null && roleTypeGrant.hasInstitutionalPrivilege(grantType)) {
if (roleTypeGrant != null && roleTypeGrant.hasInstitutionalPrivilege(privilegeType)) {
return true;
}
}

View file

@ -10,9 +10,13 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
import java.security.Principal;
import org.springframework.web.bind.WebDataBinder;
/** A service to get the authenticated user from current request */
public interface UserService {
String USERS_INSTITUTION_AS_DEFAULT = "USERS_INSTITUTION_AS_DEFAULT";
/** Use this to get the current User within a request-response thread cycle.
*
* @return the SEBServerUser instance of the current request
@ -46,4 +50,6 @@ public interface UserService {
* @return an overall super user with all rights */
SEBServerUser getSuperUser();
void addUsersInstitutionDefaultPropertySupport(final WebDataBinder binder);
}

View file

@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
import java.beans.PropertyEditorSupport;
import java.security.Principal;
import java.util.Collection;
@ -20,6 +21,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.WebDataBinder;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -78,6 +80,22 @@ public class UserServiceImpl implements UserService {
return SUPER_USER;
}
@Override
public void addUsersInstitutionDefaultPropertySupport(final WebDataBinder binder) {
final PropertyEditorSupport usersInstitutionDefaultEditor = new PropertyEditorSupport() {
@Override
public void setAsText(final String text) throws IllegalArgumentException {
if (UserService.USERS_INSTITUTION_AS_DEFAULT.equals(text)) {
setValue(getCurrentUser().institutionId());
} else {
setValue((text == null) ? null : Long.decode(text));
}
}
};
binder.registerCustomEditor(Long.class, usersInstitutionDefaultEditor);
}
// 1. OAuth2Authentication strategy
@Lazy
@Component

View file

@ -21,6 +21,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@Service
@ -49,44 +50,56 @@ public class BulkActionService {
action.alreadyProcessed = true;
}
public void doBulkAction(final BulkAction action) {
checkProcessing(action);
public Result<BulkAction> doBulkAction(final BulkAction action) {
return Result.tryCatch(() -> {
final BulkActionSupportDAO<?> supportForSource = this.supporter.get(action.sourceType);
if (supportForSource == null) {
action.alreadyProcessed = true;
return;
}
checkProcessing(action);
collectDependencies(action);
if (!action.dependencies.isEmpty()) {
// process dependencies first...
final List<BulkActionSupportDAO<?>> dependancySupporter =
getDependancySupporter(action);
for (final BulkActionSupportDAO<?> support : dependancySupporter) {
action.result.addAll(support.processBulkAction(action));
final BulkActionSupportDAO<?> supportForSource = this.supporter
.get(action.sourceType);
if (supportForSource == null) {
action.alreadyProcessed = true;
throw new IllegalArgumentException("No bulk action support for: " + action);
}
}
action.result.addAll(supportForSource.processBulkAction(action));
collectDependencies(action);
processUserActivityLog(action);
action.alreadyProcessed = true;
if (!action.dependencies.isEmpty()) {
// process dependencies first...
final List<BulkActionSupportDAO<?>> dependancySupporter =
getDependancySupporter(action);
for (final BulkActionSupportDAO<?> support : dependancySupporter) {
action.result.addAll(support.processBulkAction(action));
}
}
action.result.addAll(supportForSource.processBulkAction(action));
processUserActivityLog(action);
action.alreadyProcessed = true;
return action;
});
}
public EntityProcessingReport createReport(final BulkAction action) {
public Result<EntityProcessingReport> createReport(final BulkAction action) {
if (!action.alreadyProcessed) {
doBulkAction(action);
return doBulkAction(action)
.flatMap(this::createFullReport);
} else {
return createFullReport(action);
}
}
// TODO
private Result<EntityProcessingReport> createFullReport(final BulkAction action) {
return Result.tryCatch(() -> {
return new EntityProcessingReport(
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyMap());
// TODO
return new EntityProcessingReport(
action.sources,
Collections.emptyList(),
Collections.emptyList());
});
}
private void processUserActivityLog(final BulkAction action) {
@ -98,7 +111,7 @@ public class BulkActionService {
this.userActivityLogDAO.log(
action.type.activityType,
key.entityType,
key.entityId,
key.modelId,
"bulk action dependency");
}
@ -106,7 +119,7 @@ public class BulkActionService {
this.userActivityLogDAO.log(
action.type.activityType,
key.entityType,
key.entityId,
key.modelId,
"bulk action source");
}
}

View file

@ -32,7 +32,21 @@ public interface EntityDAO<T extends Entity> {
* @param id the data base identifier of the entity
* @return Result refer the Entity instance with the specified database identifier or refer to an error if
* happened */
Result<T> byId(Long id);
Result<T> byPK(Long id);
/** Use this to get an Entity instance of concrete type by model identifier
*
* NOTE: A model identifier may differ from the string representation of the database identifier
* but usually they are the same.
*
* @param id the model identifier
* @return Result refer the Entity instance with the specified model identifier or refer to an error if
* happened */
default Result<T> byModelId(final String id) {
return Result.tryCatch(() -> {
return Long.parseLong(id);
}).flatMap(this::byPK);
}
/** Use this to get a Collection of all entities of concrete type that matches a given predicate.
*
@ -104,7 +118,7 @@ public interface EntityDAO<T extends Entity> {
*
* @param keys Collection of EntityKey of various types
* @return List of id's (PK's) from the given key collection that match the concrete EntityType */
default List<Long> extractIdsFromKeys(final Collection<EntityKey> keys) {
default List<Long> extractPKsFromKeys(final Collection<EntityKey> keys) {
if (keys == null) {
return Collections.emptyList();
@ -114,7 +128,7 @@ public interface EntityDAO<T extends Entity> {
return keys
.stream()
.filter(key -> key.entityType == entityType)
.map(key -> Long.valueOf(key.entityId))
.map(key -> Long.valueOf(key.modelId))
.collect(Collectors.toList());
}

View file

@ -10,6 +10,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
import java.util.Collection;
import org.joda.time.DateTime;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.util.Result;
@ -27,8 +29,10 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam>, BulkActionSupportDA
String name,
Exam.ExamStatus status,
Exam.ExamType type,
Long startTime,
DateTime from,
String owner,
Boolean active);
Result<Exam> save(Exam exam);
}

View file

@ -84,6 +84,7 @@ public interface UserActivityLogDAO extends UserRelatedEntityDAO<UserActivityLog
}
Result<Collection<UserActivityLog>> all(
Long InstitutionId,
String userId,
Long from,
Long to,

View file

@ -26,17 +26,11 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSuppor
* within SEBServerUser. */
public interface UserDAO extends ActivatableEntityDAO<UserInfo>, BulkActionSupportDAO<UserInfo> {
/** Use this to get UserInfo by users UUID
*
* @param uuid The UUID of the user to get UserInfo from
* @return a Result of UserInfo data from user with the specified UUID. Or an exception result on error case */
Result<UserInfo> byUuid(String uuid);
/** Use this to get the user id (PK) from a given UUID.
*
* @param uuid The UUID of the user
* @return the user id (PK) from a given UUID. */
Result<Long> pkForUUID(String uuid);
Result<Long> pkForModelId(String uuid);
/** Use this to get UserInfo by users username
*

View file

@ -22,6 +22,7 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
import org.springframework.context.annotation.Lazy;
@ -67,7 +68,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override
@Transactional(readOnly = true)
public Result<Exam> byId(final Long id) {
public Result<Exam> byPK(final Long id) {
return recordById(id)
.flatMap(this::toDomainModel);
}
@ -108,7 +109,7 @@ public class ExamDAOImpl implements ExamDAO {
final String name,
final ExamStatus status,
final ExamType type,
final Long startTime,
final DateTime from,
final String owner,
final Boolean active) {
@ -121,8 +122,8 @@ public class ExamDAOImpl implements ExamDAO {
}
}
if (startTime != null) {
if (exam.startTime.getMillis() < startTime.longValue()) {
if (from != null) {
if (exam.startTime.isAfter(from)) {
return false;
}
}
@ -167,10 +168,40 @@ public class ExamDAOImpl implements ExamDAO {
return Result.ofTODO();
}
@Override
public Result<Exam> save(final Exam exam) {
if (exam == null) {
return Result.ofError(new NullPointerException("exam has null-reference"));
}
if (exam.id == null) {
return Result.ofError(new IllegalArgumentException("exam.id has null-reference"));
}
return update(exam)
.flatMap(this::toDomainModel);
}
private Result<ExamRecord> update(final Exam exam) {
return Result.tryCatch(() -> {
final ExamRecord examRecord = new ExamRecord(
exam.id,
null, null, null, null,
(exam.supporter != null)
? StringUtils.join(exam.supporter, Constants.LIST_SEPARATOR_CHAR)
: null,
(exam.type != null) ? exam.type.name() : null,
(exam.status != null) ? exam.status.name() : null,
BooleanUtils.toIntegerObject(exam.active));
this.examRecordMapper.updateByPrimaryKeySelective(examRecord);
return this.examRecordMapper.selectByPrimaryKey(exam.id);
});
}
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
final ExamRecord examRecord = new ExamRecord(null, null, null, null, null,
null, null, null, BooleanUtils.toInteger(active));
@ -196,7 +227,7 @@ public class ExamDAOImpl implements ExamDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
try {
@ -235,7 +266,7 @@ public class ExamDAOImpl implements ExamDAO {
@Transactional(readOnly = true)
public Result<Collection<Exam>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final List<Long> ids = extractIdsFromKeys(keys);
final List<Long> ids = extractPKsFromKeys(keys);
return this.examRecordMapper.selectByExample()
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
.build()
@ -247,7 +278,7 @@ public class ExamDAOImpl implements ExamDAO {
return Result.tryCatch(() -> {
return this.examRecordMapper.selectIdsByExample()
.where(ExamRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
isEqualTo(Long.valueOf(institutionKey.modelId)))
.build()
.execute()
.stream()
@ -260,7 +291,7 @@ public class ExamDAOImpl implements ExamDAO {
return Result.tryCatch(() -> {
return this.examRecordMapper.selectIdsByExample()
.where(ExamRecordDynamicSqlSupport.lmsSetupId,
isEqualTo(Long.valueOf(lmsSetupKey.entityId)))
isEqualTo(Long.valueOf(lmsSetupKey.modelId)))
.build()
.execute()
.stream()

View file

@ -56,7 +56,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
@Override
@Transactional(readOnly = true)
public Result<Institution> byId(final Long id) {
public Result<Institution> byPK(final Long id) {
return recordById(id)
.flatMap(InstitutionDAOImpl::toDomainModel);
}
@ -123,7 +123,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
final InstitutionRecord institutionRecord = new InstitutionRecord(
null, null, null, BooleanUtils.toInteger(active), null);
@ -147,7 +147,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
try {
this.institutionRecordMapper.deleteByExample()
@ -177,7 +177,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
@Transactional(readOnly = true)
public Result<Collection<Institution>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final List<Long> ids = extractIdsFromKeys(keys);
final List<Long> ids = extractPKsFromKeys(keys);
return this.institutionRecordMapper.selectByExample()
.where(InstitutionRecordDynamicSqlSupport.id, isIn(ids))
@ -217,19 +217,18 @@ public class InstitutionDAOImpl implements InstitutionDAO {
}
private Result<InstitutionRecord> update(final Institution institution) {
return recordById(institution.id)
.map(record -> {
return Result.tryCatch(() -> {
final InstitutionRecord newRecord = new InstitutionRecord(
institution.id,
institution.name,
institution.urlSuffix,
null,
institution.logoImage);
final InstitutionRecord newRecord = new InstitutionRecord(
institution.id,
institution.name,
institution.urlSuffix,
null,
institution.logoImage);
this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.institutionRecordMapper.selectByPrimaryKey(institution.id);
});
this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.institutionRecordMapper.selectByPrimaryKey(institution.id);
});
}
private static Result<Institution> toDomainModel(final InstitutionRecord record) {

View file

@ -55,7 +55,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
@Override
@Transactional(readOnly = true)
public Result<LmsSetup> byId(final Long id) {
public Result<LmsSetup> byPK(final Long id) {
return recordById(id)
.flatMap(LmsSetupDAOImpl::toDomainModel);
}
@ -137,7 +137,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
final LmsSetupRecord lmsSetupRecord = new LmsSetupRecord(
null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toIntegerObject(active));
@ -162,7 +162,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
try {
this.lmsSetupRecordMapper.deleteByExample()
@ -196,7 +196,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
@Transactional(readOnly = true)
public Result<Collection<LmsSetup>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final List<Long> ids = extractIdsFromKeys(keys);
final List<Long> ids = extractPKsFromKeys(keys);
return this.lmsSetupRecordMapper.selectByExample()
.where(LmsSetupRecordDynamicSqlSupport.id, isIn(ids))
@ -213,7 +213,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
return Result.tryCatch(() -> {
return this.lmsSetupRecordMapper.selectIdsByExample()
.where(LmsSetupRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
isEqualTo(Long.valueOf(institutionKey.modelId)))
.build()
.execute()
.stream()
@ -271,25 +271,24 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
}
private Result<LmsSetupRecord> update(final LmsSetup lmsSetup) {
return recordById(lmsSetup.id)
.map(record -> {
return Result.tryCatch(() -> {
final LmsSetupRecord newRecord = new LmsSetupRecord(
lmsSetup.id,
lmsSetup.institutionId,
lmsSetup.name,
(lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null,
lmsSetup.lmsApiUrl,
lmsSetup.lmsAuthName,
lmsSetup.lmsAuthSecret,
lmsSetup.lmsRestApiToken,
lmsSetup.sebAuthName,
lmsSetup.sebAuthSecret,
null);
final LmsSetupRecord newRecord = new LmsSetupRecord(
lmsSetup.id,
lmsSetup.institutionId,
lmsSetup.name,
(lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null,
lmsSetup.lmsApiUrl,
lmsSetup.lmsAuthName,
lmsSetup.lmsAuthSecret,
lmsSetup.lmsRestApiToken,
lmsSetup.sebAuthName,
lmsSetup.sebAuthSecret,
null);
this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id);
});
this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id);
});
}
}

View file

@ -34,8 +34,6 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRe
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserActivityLogRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
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.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
@ -49,18 +47,15 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
private final UserActivityLogRecordMapper userLogRecordMapper;
private final UserService userService;
private final AuthorizationGrantService authorizationGrantService;
private final PaginationService paginationService;
public UserActivityLogDAOImpl(
final UserActivityLogRecordMapper userLogRecordMapper,
final UserService userService,
final AuthorizationGrantService authorizationGrantService,
final PaginationService paginationService) {
this.userLogRecordMapper = userLogRecordMapper;
this.userService = userService;
this.authorizationGrantService = authorizationGrantService;
this.paginationService = paginationService;
}
@ -172,7 +167,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
@Override
@Transactional(readOnly = true)
public Result<UserActivityLog> byId(final Long id) {
public Result<UserActivityLog> byPK(final Long id) {
return Result.tryCatch(() -> this.userLogRecordMapper.selectByPrimaryKey(id))
.flatMap(UserActivityLogDAOImpl::toDomainModel);
}
@ -180,7 +175,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
try {
this.userLogRecordMapper.deleteByExample()
@ -202,12 +197,24 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
@Override
@Transactional(readOnly = true)
public Result<Collection<UserActivityLog>> getAllForUser(final String userUuid) {
return all(userUuid, null, null, model -> true);
return Result.tryCatch(() -> {
return this.userLogRecordMapper.selectByExample()
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualTo(userUuid))
.build()
.execute()
.stream()
.map(UserActivityLogDAOImpl::toDomainModel)
.flatMap(Result::skipOnError)
.collect(Collectors.toList());
});
}
@Override
@Transactional(readOnly = true)
public Result<Collection<UserActivityLog>> all(
final Long institutionId,
final String userId,
final Long from,
final Long to,
@ -218,57 +225,30 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
? predicate
: model -> true;
final boolean basePrivilege = this.authorizationGrantService.hasBasePrivilege(
EntityType.USER_ACTIVITY_LOG,
PrivilegeType.READ_ONLY);
final Long institutionId = (basePrivilege)
? null
: this.userService.getCurrentUser().institutionId();
return (institutionId == null)
? this.userLogRecordMapper.selectByExample()
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userId))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(from))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isLessThanWhenPresent(to))
.build()
.execute()
.stream()
.filter(_predicate)
.map(UserActivityLogDAOImpl::toDomainModel)
.flatMap(Result::skipOnError)
.collect(Collectors.toList())
: this.userLogRecordMapper.selectByExample()
.join(UserRecordDynamicSqlSupport.userRecord)
.on(
UserRecordDynamicSqlSupport.uuid,
SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid))
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userId))
.and(
UserRecordDynamicSqlSupport.institutionId,
SqlBuilder.isEqualToWhenPresent(institutionId))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(from))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isLessThanWhenPresent(to))
.build()
.execute()
.stream()
.filter(_predicate)
.map(UserActivityLogDAOImpl::toDomainModel)
.flatMap(Result::skipOnError)
.collect(Collectors.toList());
return this.userLogRecordMapper.selectByExample()
.join(UserRecordDynamicSqlSupport.userRecord)
.on(
UserRecordDynamicSqlSupport.uuid,
SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid))
.where(
UserRecordDynamicSqlSupport.institutionId,
SqlBuilder.isEqualTo(institutionId))
.and(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userId))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(from))
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isLessThanWhenPresent(to))
.build()
.execute()
.stream()
.filter(_predicate)
.map(UserActivityLogDAOImpl::toDomainModel)
.flatMap(Result::skipOnError)
.collect(Collectors.toList());
});
}

View file

@ -83,22 +83,22 @@ public class UserDaoImpl implements UserDAO {
@Override
@Transactional(readOnly = true)
public Result<UserInfo> byId(final Long id) {
public Result<UserInfo> byPK(final Long id) {
return Result.tryCatch(() -> this.userRecordMapper.selectByPrimaryKey(id))
.flatMap(this::toDomainModel);
}
@Override
@Transactional(readOnly = true)
public Result<UserInfo> byUuid(final String uuid) {
return recordByUUID(uuid)
public Result<UserInfo> byModelId(final String modelId) {
return recordByUUID(modelId)
.flatMap(this::toDomainModel);
}
@Override
@Transactional(readOnly = true)
public Result<Long> pkForUUID(final String uuid) {
return recordByUUID(uuid)
public Result<Long> pkForModelId(final String modelId) {
return recordByUUID(modelId)
.map(r -> r.getId());
}
@ -191,7 +191,7 @@ public class UserDaoImpl implements UserDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
final UserRecord userRecord = new UserRecord(
null, null, null, null, null, null, null, null, null,
BooleanUtils.toIntegerObject(active));
@ -216,7 +216,7 @@ public class UserDaoImpl implements UserDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
final List<Long> ids = extractPKsFromKeys(all);
try {
this.userRecordMapper.deleteByExample()
@ -259,7 +259,7 @@ public class UserDaoImpl implements UserDAO {
@Transactional(readOnly = true)
public Result<Collection<UserInfo>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final List<Long> ids = extractIdsFromKeys(keys);
final List<Long> ids = extractPKsFromKeys(keys);
return this.userRecordMapper.selectByExample()
.where(InstitutionRecordDynamicSqlSupport.id, isIn(ids))
@ -273,12 +273,12 @@ public class UserDaoImpl implements UserDAO {
}
@Override
public List<Long> extractIdsFromKeys(final Collection<EntityKey> keys) {
public List<Long> extractPKsFromKeys(final Collection<EntityKey> keys) {
if (keys == null || keys.isEmpty() || keys.iterator().next().isIdPK) {
return UserDAO.super.extractIdsFromKeys(keys);
return UserDAO.super.extractPKsFromKeys(keys);
} else {
final List<String> uuids = keys.stream()
.map(key -> key.entityId)
.map(key -> key.modelId)
.collect(Collectors.toList());
try {
@ -299,7 +299,7 @@ public class UserDaoImpl implements UserDAO {
return Result.tryCatch(() -> {
return this.userRecordMapper.selectIdsByExample()
.where(UserRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
isEqualTo(Long.valueOf(institutionKey.modelId)))
.build()
.execute()
.stream()

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms;
import java.io.InputStream;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.util.Result;
@ -17,8 +19,8 @@ public interface LmsAPIService {
Result<LmsAPITemplate> createLmsAPITemplate(LmsSetup lmsSetup);
Result<byte[]> createSEBStartConfiguration(Long lmsSetupId);
Result<InputStream> createSEBStartConfiguration(Long lmsSetupId);
Result<byte[]> createSEBStartConfiguration(LmsSetup lmsSetup);
Result<InputStream> createSEBStartConfiguration(LmsSetup lmsSetup);
}

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
import java.io.InputStream;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -30,7 +32,7 @@ public class LmsAPIServiceImpl implements LmsAPIService {
@Override
public Result<LmsAPITemplate> createLmsAPITemplate(final Long lmsSetupId) {
return this.lmsSetupDAO
.byId(lmsSetupId)
.byPK(lmsSetupId)
.flatMap(this::createLmsAPITemplate);
}
@ -46,14 +48,14 @@ public class LmsAPIServiceImpl implements LmsAPIService {
}
@Override
public Result<byte[]> createSEBStartConfiguration(final Long lmsSetupId) {
public Result<InputStream> createSEBStartConfiguration(final Long lmsSetupId) {
return this.lmsSetupDAO
.byId(lmsSetupId)
.byPK(lmsSetupId)
.flatMap(this::createSEBStartConfiguration);
}
@Override
public Result<byte[]> createSEBStartConfiguration(final LmsSetup lmsSetup) {
public Result<InputStream> createSEBStartConfiguration(final LmsSetup lmsSetup) {
// TODO implementation of creation of SEB start configuration for specified LmsSetup
// A SEB start configuration should at least contain the SEB-Client-Credentials to access the SEB Server API

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019 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.weblayer.api;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
public abstract class ActivatableEntityController<T extends GrantEntity> extends EntityController<T> {
public ActivatableEntityController(
final AuthorizationGrantService authorizationGrantService,
final BulkActionService bulkActionService,
final EntityDAO<T> entityDAO) {
super(authorizationGrantService, bulkActionService, entityDAO);
}
@RequestMapping(path = "/{id}/activate", method = RequestMethod.POST)
public EntityProcessingReport activate(@PathVariable final String id) {
return setActive(id, true)
.getOrThrow();
}
@RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST)
public EntityProcessingReport deactivate(@PathVariable final String id) {
return setActive(id, false)
.getOrThrow();
}
@RequestMapping(path = "/{id}/delete", method = RequestMethod.DELETE)
public EntityProcessingReport delete(@PathVariable final String id) {
return deactivate(id);
}
private Result<EntityProcessingReport> setActive(final String id, final boolean active) {
final EntityType entityType = this.entityDAO.entityType();
final BulkAction bulkAction = new BulkAction(
(active) ? Type.ACTIVATE : Type.DEACTIVATE,
entityType,
new EntityKey(id, entityType));
return this.entityDAO.byModelId(id)
.flatMap(entity -> this.authorizationGrantService.checkGrantOnEntity(
entity,
PrivilegeType.WRITE))
.flatMap(entity -> this.bulkActionService.createReport(bulkAction));
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019 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.weblayer.api;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
public abstract class EntityController<T extends GrantEntity> {
protected final AuthorizationGrantService authorizationGrantService;
protected final BulkActionService bulkActionService;
protected final EntityDAO<T> entityDAO;
protected EntityController(
final AuthorizationGrantService authorizationGrantService,
final BulkActionService bulkActionService,
final EntityDAO<T> entityDAO) {
this.authorizationGrantService = authorizationGrantService;
this.bulkActionService = bulkActionService;
this.entityDAO = entityDAO;
}
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public T accountInfo(@PathVariable final String id) {
return this.entityDAO
.byModelId(id)
.flatMap(entity -> this.authorizationGrantService.checkGrantOnEntity(
entity,
PrivilegeType.READ_ONLY))
.getOrThrow();
}
@RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE)
public EntityProcessingReport hardDeleteUser(@PathVariable final String id) {
final EntityType entityType = this.entityDAO.entityType();
final BulkAction bulkAction = new BulkAction(
Type.HARD_DELETE,
entityType,
new EntityKey(id, entityType));
return this.entityDAO.byModelId(id)
.flatMap(entity -> this.authorizationGrantService.checkGrantOnEntity(
entity,
PrivilegeType.WRITE))
.flatMap(entity -> this.bulkActionService.createReport(bulkAction))
.getOrThrow();
}
}

View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2019 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.weblayer.api;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
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.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
@WebServiceProfile
@RestController
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_EXAM_ADMINISTRATION)
public class ExamAdministrationController {
private final AuthorizationGrantService authorizationGrantService;
private final UserActivityLogDAO userActivityLogDAO;
private final ExamDAO examDAO;
private final PaginationService paginationService;
private final BulkActionService bulkActionService;
public ExamAdministrationController(
final AuthorizationGrantService authorizationGrantService,
final UserActivityLogDAO userActivityLogDAO,
final ExamDAO examDAO,
final PaginationService paginationService,
final BulkActionService bulkActionService) {
this.authorizationGrantService = authorizationGrantService;
this.userActivityLogDAO = userActivityLogDAO;
this.examDAO = examDAO;
this.paginationService = paginationService;
this.bulkActionService = bulkActionService;
}
@InitBinder
public void initBinder(final WebDataBinder binder) throws Exception {
this.authorizationGrantService
.getUserService()
.addUsersInstitutionDefaultPropertySupport(binder);
}
@RequestMapping(method = RequestMethod.GET)
public Collection<Exam> getAll(
@RequestParam(
name = Exam.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Exam.FILTER_ATTR_LMS_SETUP, required = false) final Long lmsSetupId,
@RequestParam(name = Exam.FILTER_ATTR_ACTIVE, required = false) final Boolean active,
@RequestParam(name = Exam.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = Exam.FILTER_ATTR_FROM, required = false) final String from,
@RequestParam(name = Exam.FILTER_ATTR_STATUS, required = false) final ExamStatus status,
@RequestParam(name = Exam.FILTER_ATTR_TYPE, required = false) final ExamType type,
@RequestParam(name = Exam.FILTER_ATTR_OWNER, required = false) final String owner) {
checkBaseReadPrivilege(institutionId);
this.paginationService.setDefaultLimit(ExamRecordDynamicSqlSupport.examRecord);
return getExams(institutionId, lmsSetupId, active, name, from, status, type, owner);
}
@RequestMapping(path = "/page", method = RequestMethod.GET)
public Page<Exam> getPage(
@RequestParam(
name = Exam.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Exam.FILTER_ATTR_LMS_SETUP, required = false) final Long lmsSetupId,
@RequestParam(name = Exam.FILTER_ATTR_ACTIVE, required = false) final Boolean active,
@RequestParam(name = Exam.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = Exam.FILTER_ATTR_FROM, required = false) final String from,
@RequestParam(name = Exam.FILTER_ATTR_STATUS, required = false) final ExamStatus status,
@RequestParam(name = Exam.FILTER_ATTR_TYPE, required = false) final ExamType type,
@RequestParam(name = Exam.FILTER_ATTR_OWNER, required = false) final String owner,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
checkBaseReadPrivilege(institutionId);
// NOTE: several attributes for sorting may be originated by the QuizData from LMS not by the database
// of the SEB Server. Therefore in the case we have no or the default sorting we can use the
// native PaginationService within MyBatis and SQL. For the other cases we need an in-line sorting and paging
if (StringUtils.isBlank(sortBy) ||
this.paginationService.isNativeSortingSupported(ExamRecordDynamicSqlSupport.examRecord, sortBy)) {
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
ExamRecordDynamicSqlSupport.examRecord,
() -> getExams(institutionId, lmsSetupId, active, name, from, status, type, owner));
} else {
final int pageNum = this.paginationService.getPageNumber(pageNumber);
final int pSize = this.paginationService.getPageSize(pageSize);
final List<Exam> exams = new ArrayList<>(
getExams(institutionId, lmsSetupId, active, name, from, status, type, owner));
if (!StringUtils.isBlank(sortBy)) {
if (sortBy.equals(QuizData.QUIZ_ATTR_NAME)) {
Collections.sort(exams, (exam1, exam2) -> exam1.name.compareTo(exam2.name));
}
if (sortBy.equals(QuizData.FILTER_ATTR_START_TIME)) {
Collections.sort(exams, (exam1, exam2) -> exam1.startTime.compareTo(exam2.startTime));
}
}
if (SortOrder.DESCENDING == sortOrder) {
Collections.reverse(exams);
}
return new Page<>(
exams.size() / pSize,
pageNum,
sortBy,
sortOrder,
exams.subList(pageNum * pSize, pageNum * pSize + pSize));
}
}
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public Exam byId(@PathVariable final Long id) {
return this.examDAO
.byPK(id)
.flatMap(exam -> this.authorizationGrantService.checkGrantOnEntity(
exam,
PrivilegeType.READ_ONLY))
.getOrThrow();
}
@RequestMapping(path = "/save", method = RequestMethod.POST)
public Exam save(@Valid @RequestBody final Exam exam) {
return this.authorizationGrantService
.checkGrantOnEntity(exam, PrivilegeType.MODIFY)
.flatMap(this.examDAO::save)
.flatMap(entity -> this.userActivityLogDAO.log(ActivityType.MODIFY, entity))
.getOrThrow();
}
@RequestMapping(path = "/{id}/activate", method = RequestMethod.POST)
public EntityProcessingReport activate(@PathVariable final Long id) {
return setActive(id, true)
.getOrThrow();
}
@RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST)
public EntityProcessingReport deactivate(@PathVariable final Long id) {
return setActive(id, false)
.getOrThrow();
}
private Result<EntityProcessingReport> setActive(final Long id, final boolean active) {
return this.bulkActionService.createReport(new BulkAction(
(active) ? Type.ACTIVATE : Type.DEACTIVATE,
EntityType.LMS_SETUP,
new EntityKey(id, EntityType.LMS_SETUP)));
}
private Collection<Exam> getExams(
final Long institutionId,
final Long lmsSetupId,
final Boolean active,
final String name,
final String from,
final ExamStatus status,
final ExamType type,
final String owner) {
this.authorizationGrantService.checkPrivilege(
EntityType.EXAM,
PrivilegeType.READ_ONLY,
institutionId);
final DateTime _from = (from != null)
? DateTime.parse(from, Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS)
: null;
return this.examDAO.allMatching(
institutionId,
lmsSetupId,
name,
status,
type,
_from,
owner,
active).getOrThrow();
}
private void checkBaseReadPrivilege(final Long institutionId) {
this.authorizationGrantService.checkPrivilege(
EntityType.EXAM,
PrivilegeType.READ_ONLY,
institutionId);
}
}

View file

@ -21,8 +21,8 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
@ -62,24 +62,18 @@ public class InstitutionController {
@RequestMapping(path = "/self", method = RequestMethod.GET)
public Institution getOwn() {
checkBaseReadPrivilege();
final SEBServerUser currentUser = this.authorizationGrantService
.getUserService()
.getCurrentUser();
final Long institutionId = currentUser.institutionId();
return this.institutionDAO.byId(institutionId).getOrThrow();
final Long institutionId = currentUser.institutionId();
return this.institutionDAO.byPK(institutionId).getOrThrow();
}
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public Institution getById(@PathVariable final Long id) {
checkBaseReadPrivilege();
return this.institutionDAO
.byId(id)
.byPK(id)
.flatMap(inst -> this.authorizationGrantService.checkGrantOnEntity(
inst,
PrivilegeType.READ_ONLY))
@ -90,8 +84,6 @@ public class InstitutionController {
public Collection<Institution> getAll(
@RequestParam(name = Institution.FILTER_ATTR_ACTIVE, required = false) final Boolean active) {
checkBaseReadPrivilege();
if (!this.authorizationGrantService.hasBasePrivilege(
EntityType.INSTITUTION,
PrivilegeType.READ_ONLY)) {
@ -126,13 +118,15 @@ public class InstitutionController {
}
@RequestMapping(path = "/{id}/activate", method = RequestMethod.POST)
public Institution activate(@PathVariable final Long id) {
return setActive(id, true);
public EntityProcessingReport activate(@PathVariable final Long id) {
return setActive(id, true)
.getOrThrow();
}
@RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST)
public Institution deactivate(@PathVariable final Long id) {
return setActive(id, false);
public EntityProcessingReport deactivate(@PathVariable final Long id) {
return setActive(id, false)
.getOrThrow();
}
@RequestMapping(path = "/{id}/delete", method = RequestMethod.DELETE)
@ -142,7 +136,8 @@ public class InstitutionController {
return this.bulkActionService.createReport(new BulkAction(
Type.DEACTIVATE,
EntityType.INSTITUTION,
new EntityKey(id, EntityType.INSTITUTION)));
new EntityKey(id, EntityType.INSTITUTION)))
.getOrThrow();
}
@RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE)
@ -152,7 +147,8 @@ public class InstitutionController {
return this.bulkActionService.createReport(new BulkAction(
Type.HARD_DELETE,
EntityType.INSTITUTION,
new EntityKey(id, EntityType.INSTITUTION)));
new EntityKey(id, EntityType.INSTITUTION)))
.getOrThrow();
}
private void checkPrivilegeForInstitution(final Long id, final PrivilegeType type) {
@ -160,24 +156,21 @@ public class InstitutionController {
EntityType.INSTITUTION,
type);
this.institutionDAO.byId(id)
this.institutionDAO.byPK(id)
.flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity(
institution,
type))
.getOrThrow();
}
private Institution setActive(final Long id, final boolean active) {
private Result<EntityProcessingReport> setActive(final Long id, final boolean active) {
checkPrivilegeForInstitution(id, PrivilegeType.MODIFY);
this.bulkActionService.doBulkAction(new BulkAction(
return this.bulkActionService.createReport(new BulkAction(
(active) ? Type.ACTIVATE : Type.DEACTIVATE,
EntityType.INSTITUTION,
new EntityKey(id, EntityType.INSTITUTION)));
return this.institutionDAO
.byId(id)
.getOrThrow();
}
private Result<Institution> save(final Institution institution, final PrivilegeType privilegeType) {
@ -192,10 +185,4 @@ public class InstitutionController {
.flatMap(inst -> this.userActivityLogDAO.log(activityType, inst));
}
private void checkBaseReadPrivilege() {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.INSTITUTION,
PrivilegeType.READ_ONLY);
}
}

View file

@ -8,12 +8,18 @@
package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.io.InputStream;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -30,9 +36,8 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
@ -66,44 +71,42 @@ public class LmsSetupController {
this.lmsAPIService = lmsAPIService;
}
@InitBinder
public void initBinder(final WebDataBinder binder) throws Exception {
this.authorizationGrantService
.getUserService()
.addUsersInstitutionDefaultPropertySupport(binder);
}
@RequestMapping(method = RequestMethod.GET)
public Collection<LmsSetup> getAll(
@RequestParam(name = LmsSetup.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(
name = LmsSetup.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = LmsSetup.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) {
checkBaseReadPrivilege();
final SEBServerUser currentUser = this.authorizationGrantService
.getUserService()
.getCurrentUser();
final Long usersInstitution = currentUser.institutionId();
final Long instId = (institutionId != null) ? institutionId : usersInstitution;
if (!this.authorizationGrantService.hasBasePrivilege(
EntityType.LMS_SETUP,
PrivilegeType.READ_ONLY) &&
!instId.equals(usersInstitution)) {
throw new PermissionDeniedException(
EntityType.LMS_SETUP,
PrivilegeType.READ_ONLY,
currentUser.getUserInfo().uuid);
}
checkReadPrivilege(institutionId);
return this.lmsSetupDAO
.allMatching(instId, name, lmsType, active)
.allMatching(institutionId, name, lmsType, active)
.getOrThrow();
}
@RequestMapping(path = "/names", method = RequestMethod.GET)
public Collection<EntityKeyAndName> getNames(
@RequestParam(name = LmsSetup.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(
name = LmsSetup.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = LmsSetup.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) {
checkReadPrivilege(institutionId);
return getAll(institutionId, name, lmsType, active)
.stream()
.map(LmsSetup::toName)
@ -112,13 +115,10 @@ public class LmsSetupController {
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public LmsSetup getById(@PathVariable final Long id) {
checkBaseReadPrivilege();
return this.lmsSetupDAO
.byId(id)
.flatMap(inst -> this.authorizationGrantService.checkGrantOnEntity(
inst,
.byPK(id)
.flatMap(lmsSetup -> this.authorizationGrantService.checkGrantOnEntity(
lmsSetup,
PrivilegeType.READ_ONLY))
.getOrThrow();
}
@ -127,15 +127,28 @@ public class LmsSetupController {
path = "/create_seb_config/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) // TODO check if this is the right format
public byte[] createSEBConfig(@PathVariable final Long id) {
public void downloadSEBConfig(
@PathVariable final Long id,
final HttpServletResponse response) {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.LMS_SETUP,
PrivilegeType.WRITE);
return this.lmsAPIService
.createSEBStartConfiguration(id)
.getOrThrow();
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setStatus(HttpStatus.OK.value());
try {
final InputStream sebConfigFileIn = this.lmsAPIService
.createSEBStartConfiguration(id)
.getOrThrow();
IOUtils.copyLarge(sebConfigFileIn, response.getOutputStream());
response.flushBuffer();
} catch (final Exception e) {
throw new RuntimeException("Unexpected error while trying to creae SEB start config: ", e);
}
}
@RequestMapping(path = "/create", method = RequestMethod.PUT)
@ -151,12 +164,12 @@ public class LmsSetupController {
}
@RequestMapping(path = "/{id}/activate", method = RequestMethod.POST)
public LmsSetup activate(@PathVariable final Long id) {
public EntityProcessingReport activate(@PathVariable final Long id) {
return setActive(id, true);
}
@RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST)
public LmsSetup deactivate(@PathVariable final Long id) {
public EntityProcessingReport deactivate(@PathVariable final Long id) {
return setActive(id, false);
}
@ -167,7 +180,8 @@ public class LmsSetupController {
return this.bulkActionService.createReport(new BulkAction(
Type.DEACTIVATE,
EntityType.LMS_SETUP,
new EntityKey(id, EntityType.LMS_SETUP)));
new EntityKey(id, EntityType.LMS_SETUP)))
.getOrThrow();
}
@RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE)
@ -177,31 +191,29 @@ public class LmsSetupController {
return this.bulkActionService.createReport(new BulkAction(
Type.HARD_DELETE,
EntityType.LMS_SETUP,
new EntityKey(id, EntityType.LMS_SETUP)));
new EntityKey(id, EntityType.LMS_SETUP)))
.getOrThrow();
}
private void checkPrivilegeForInstitution(final Long id, final PrivilegeType type) {
private void checkPrivilegeForInstitution(final Long lmsSetupId, final PrivilegeType type) {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.LMS_SETUP,
type);
this.lmsSetupDAO.byId(id)
this.lmsSetupDAO.byPK(lmsSetupId)
.flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity(
institution,
type))
.getOrThrow();
}
private LmsSetup setActive(final Long id, final boolean active) {
private EntityProcessingReport setActive(final Long id, final boolean active) {
checkPrivilegeForInstitution(id, PrivilegeType.MODIFY);
this.bulkActionService.doBulkAction(new BulkAction(
return this.bulkActionService.createReport(new BulkAction(
(active) ? Type.ACTIVATE : Type.DEACTIVATE,
EntityType.LMS_SETUP,
new EntityKey(id, EntityType.LMS_SETUP)));
return this.lmsSetupDAO
.byId(id)
new EntityKey(id, EntityType.LMS_SETUP)))
.getOrThrow();
}
@ -214,13 +226,14 @@ public class LmsSetupController {
return this.authorizationGrantService
.checkGrantOnEntity(lmsSetup, privilegeType)
.flatMap(this.lmsSetupDAO::save)
.flatMap(inst -> this.userActivityLogDAO.log(activityType, inst));
.flatMap(exam -> this.userActivityLogDAO.log(activityType, exam));
}
private void checkBaseReadPrivilege() {
this.authorizationGrantService.checkHasAnyPrivilege(
private void checkReadPrivilege(final Long institutionId) {
this.authorizationGrantService.checkPrivilege(
EntityType.LMS_SETUP,
PrivilegeType.READ_ONLY);
PrivilegeType.READ_ONLY,
institutionId);
}
}

View file

@ -74,19 +74,20 @@ public class QuizImportController {
@RequestParam(name = LMS_SETUP.ATTR_ID, required = true) final Long lmsSetupId,
@RequestParam(name = QuizData.FILTER_ATTR_NAME, required = false) final String nameLike,
@RequestParam(name = QuizData.FILTER_ATTR_START_TIME, required = false) final String startTime,
@RequestParam(name = QuizData.PAGE_ATTR_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = QuizData.PAGE_ATTR_SIZE, required = false) final Integer pageSize,
@RequestParam(name = QuizData.PAGE_ATTR_SORT_BY, required = false) final String orderBy,
@RequestParam(name = QuizData.PAGE_ATTR_SORT_ORDER, required = false) final String sortOrder) {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.EXAM,
PrivilegeType.READ_ONLY);
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String orderBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final String sortOrder) {
final LmsAPITemplate lmsAPITemplate = this.lmsAPIService
.createLmsAPITemplate(lmsSetupId)
.getOrThrow();
this.authorizationGrantService.checkPrivilege(
EntityType.EXAM,
PrivilegeType.READ_ONLY,
lmsAPITemplate.lmsSetup().institutionId);
return lmsAPITemplate.getQuizzesPage(
nameLike,
Utils.dateTimeStringToTimestamp(startTime, null),

View file

@ -18,6 +18,8 @@ public class RestAPI {
public static final String ENDPOINT_QUIZ_IMPORT = "/quiz";
public static final String ENDPOINT_EXAM_ADMINISTRATION = "/exam";
public static final String ENDPOINT_USER_ACTIVITY_LOG = "/useractivity";
}

View file

@ -13,15 +13,14 @@ import java.util.Collection;
import javax.validation.Valid;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.user.UserFilter;
@ -34,8 +33,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
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.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
@ -45,11 +42,10 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint;
@WebServiceProfile
@RestController
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACCOUNT)
public class UserAccountController {
public class UserAccountController extends ActivatableEntityController<UserInfo> {
private final UserDAO userDao;
private final AuthorizationGrantService authorizationGrantService;
private final UserService userService;
private final UserActivityLogDAO userActivityLogDAO;
private final PaginationService paginationService;
private final BulkActionService bulkActionService;
@ -58,34 +54,40 @@ public class UserAccountController {
public UserAccountController(
final UserDAO userDao,
final AuthorizationGrantService authorizationGrantService,
final UserService userService,
final UserActivityLogDAO userActivityLogDAO,
final PaginationService paginationService,
final BulkActionService bulkActionService,
final ApplicationEventPublisher applicationEventPublisher) {
super(authorizationGrantService, bulkActionService, userDao);
this.userDao = userDao;
this.authorizationGrantService = authorizationGrantService;
this.userService = userService;
this.userActivityLogDAO = userActivityLogDAO;
this.paginationService = paginationService;
this.bulkActionService = bulkActionService;
this.applicationEventPublisher = applicationEventPublisher;
}
@InitBinder
public void initBinder(final WebDataBinder binder) throws Exception {
this.authorizationGrantService
.getUserService()
.addUsersInstitutionDefaultPropertySupport(binder);
}
@RequestMapping(method = RequestMethod.GET)
public Collection<UserInfo> getAll(
@RequestParam(name = UserFilter.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(
name = UserFilter.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = UserFilter.FILTER_ATTR_ACTIVE, required = false) final Boolean active,
@RequestParam(name = UserFilter.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = UserFilter.FILTER_ATTR_USER_NAME, required = false) final String username,
@RequestParam(name = UserFilter.FILTER_ATTR_EMAIL, required = false) final String email,
@RequestParam(name = UserFilter.FILTER_ATTR_LOCALE, required = false) final String locale) {
// fist check if current user has any privileges for this action
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.USER,
PrivilegeType.READ_ONLY);
checkReadPrivilege(institutionId);
this.paginationService.setDefaultLimit(UserRecordDynamicSqlSupport.userRecord);
return getAll(createUserFilter(institutionId, active, name, username, email, locale));
@ -93,7 +95,10 @@ public class UserAccountController {
@RequestMapping(path = "/page", method = RequestMethod.GET)
public Page<UserInfo> getPage(
@RequestParam(name = UserFilter.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(
name = UserFilter.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = UserFilter.FILTER_ATTR_ACTIVE, required = false) final Boolean active,
@RequestParam(name = UserFilter.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = UserFilter.FILTER_ATTR_USER_NAME, required = false) final String username,
@ -104,10 +109,7 @@ public class UserAccountController {
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
// fist check if current user has any privileges for this action
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.USER,
PrivilegeType.READ_ONLY);
checkReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
@ -121,21 +123,22 @@ public class UserAccountController {
@RequestMapping(path = "/me", method = RequestMethod.GET)
public UserInfo loggedInUser() {
return this.userService
return this.authorizationGrantService
.getUserService()
.getCurrentUser()
.getUserInfo();
}
@RequestMapping(path = "/{uuid}", method = RequestMethod.GET)
public UserInfo accountInfo(@PathVariable final String uuid) {
return this.userDao
.byUuid(uuid)
.flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
userInfo,
PrivilegeType.READ_ONLY))
.getOrThrow();
}
// @Override
// @RequestMapping(path = "/{uuid}", method = RequestMethod.GET)
// public UserInfo accountInfo(@PathVariable final String uuid) {
// return this.userDao
// .byModelId(uuid)
// .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
// userInfo,
// PrivilegeType.READ_ONLY))
// .getOrThrow();
// }
@RequestMapping(path = "/create", method = RequestMethod.PUT)
public UserInfo createUser(@Valid @RequestBody final UserMod userData) {
@ -150,60 +153,52 @@ public class UserAccountController {
}
@RequestMapping(path = "/{uuid}/activate", method = RequestMethod.POST)
public UserInfo activateUser(@PathVariable final String uuid) {
return setActive(uuid, true);
}
// @Override
// @RequestMapping(path = "/{uuid}/activate", method = RequestMethod.POST)
// public EntityProcessingReport activateUser(@PathVariable final String uuid) {
// return setActive(uuid, true)
// .getOrThrow();
// }
//
// @Override
// @RequestMapping(value = "/{uuid}/deactivate", method = RequestMethod.POST)
// public EntityProcessingReport deactivateUser(@PathVariable final String uuid) {
// return setActive(uuid, false)
// .getOrThrow();
// }
//
// @Override
// @RequestMapping(path = "/{uuid}/delete", method = RequestMethod.DELETE)
// public EntityProcessingReport deleteUser(@PathVariable final String uuid) {
// checkPrivilegeForUser(uuid, PrivilegeType.WRITE);
//
// return this.bulkActionService.createReport(new BulkAction(
// Type.DEACTIVATE,
// EntityType.USER,
// new EntityKey(uuid, EntityType.USER, false)))
// .getOrThrow();
// }
@RequestMapping(value = "/{uuid}/deactivate", method = RequestMethod.POST)
public UserInfo deactivateUser(@PathVariable final String uuid) {
return setActive(uuid, false);
}
// private void checkPrivilegeForUser(final String uuid, final PrivilegeType type) {
// this.authorizationGrantService.checkHasAnyPrivilege(
// EntityType.USER,
// type);
//
// this.userDao.byModelId(uuid)
// .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
// userInfo,
// type))
// .getOrThrow();
// }
@RequestMapping(path = "/{uuid}/delete", method = RequestMethod.DELETE)
public EntityProcessingReport deleteUser(@PathVariable final String uuid) {
checkPrivilegeForUser(uuid, PrivilegeType.WRITE);
return this.bulkActionService.createReport(new BulkAction(
Type.DEACTIVATE,
EntityType.USER,
new EntityKey(uuid, EntityType.USER, false)));
}
@RequestMapping(path = "/{uuid}/hard-delete", method = RequestMethod.DELETE)
public EntityProcessingReport hardDeleteUser(@PathVariable final String uuid) {
checkPrivilegeForUser(uuid, PrivilegeType.WRITE);
return this.bulkActionService.createReport(new BulkAction(
Type.HARD_DELETE,
EntityType.USER,
new EntityKey(uuid, EntityType.USER, false)));
}
private void checkPrivilegeForUser(final String uuid, final PrivilegeType type) {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.USER,
type);
this.userDao.byUuid(uuid)
.flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(
userInfo,
type))
.getOrThrow();
}
private UserInfo setActive(final String uuid, final boolean active) {
this.checkPrivilegeForUser(uuid, PrivilegeType.MODIFY);
this.bulkActionService.doBulkAction(new BulkAction(
(active) ? Type.ACTIVATE : Type.DEACTIVATE,
EntityType.USER,
new EntityKey(uuid, EntityType.USER, false)));
return this.userDao
.byUuid(uuid)
.getOrThrow();
}
// private Result<EntityProcessingReport> setActive(final String uuid, final boolean active) {
// this.checkPrivilegeForUser(uuid, PrivilegeType.MODIFY);
//
// return this.bulkActionService.createReport(new BulkAction(
// (active) ? Type.ACTIVATE : Type.DEACTIVATE,
// EntityType.USER,
// new EntityKey(uuid, EntityType.USER, false)));
// }
private Result<UserInfo> _saveUser(final UserMod userData, final PrivilegeType privilegeType) {
@ -261,4 +256,11 @@ public class UserAccountController {
: null;
}
private void checkReadPrivilege(final Long institutionId) {
this.authorizationGrantService.checkPrivilege(
EntityType.USER,
PrivilegeType.READ_ONLY,
institutionId);
}
}

View file

@ -13,8 +13,11 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -26,11 +29,14 @@ import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserActivityLogRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
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.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@WebServiceProfile
@ -52,84 +58,113 @@ public class UserActivityLogController {
this.paginationService = paginationService;
}
@InitBinder
public void initBinder(final WebDataBinder binder) throws Exception {
this.authorizationGrantService
.getUserService()
.addUsersInstitutionDefaultPropertySupport(binder);
}
@RequestMapping(method = RequestMethod.GET)
public Collection<UserActivityLog> getAll(
@RequestParam(required = false) final Long from,
@RequestParam(required = false) final Long to,
@RequestParam(required = false) final String activityTypes,
@RequestParam(required = false) final String entityTypes) {
@RequestParam(
name = UserActivityLog.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_FROM,
required = false) final String from,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_TO,
required = false) final String to,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
required = false) final String activityTypes,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_ENTITY_TYPES,
required = false) final String entityTypes) {
checkBaseReadPrivilege();
checkBaseReadPrivilege(institutionId);
this.paginationService.setDefaultLimit(UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord);
return _getAll(null, from, to, activityTypes, entityTypes);
return _getAll(institutionId, null, from, to, activityTypes, entityTypes);
}
@RequestMapping(path = "/{userId}", method = RequestMethod.GET)
public Collection<UserActivityLog> getAllForUser(
@PathVariable final String userId,
@RequestParam(required = false) final Long from,
@RequestParam(required = false) final Long to,
@RequestParam(required = false) final String activityTypes,
@RequestParam(required = false) final String entityTypes) {
@RequestParam(
name = UserActivityLog.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = UserActivityLog.FILTER_ATTR_FROM, required = false) final String from,
@RequestParam(name = UserActivityLog.FILTER_ATTR_TO, required = false) final String to,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
required = false) final String activityTypes,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ENTITY_TYPES, required = false) final String entityTypes) {
checkBaseReadPrivilege();
checkBaseReadPrivilege(institutionId);
this.paginationService.setDefaultLimit(UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord);
return _getAll(userId, from, to, activityTypes, entityTypes);
return _getAll(institutionId, userId, from, to, activityTypes, entityTypes);
}
@RequestMapping(path = "/page", method = RequestMethod.GET)
public Page<UserActivityLog> getPage(
@RequestParam(required = false) final Long from,
@RequestParam(required = false) final Long to,
@RequestParam(required = false) final String activityTypes,
@RequestParam(required = false) final String entityTypes,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = UserActivityLog.FILTER_ATTR_FROM, required = false) final String from,
@RequestParam(name = UserActivityLog.FILTER_ATTR_TO, required = false) final String to,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
required = false) final String activityTypes,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ENTITY_TYPES, required = false) final String entityTypes,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
checkBaseReadPrivilege();
checkBaseReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
UserRecordDynamicSqlSupport.userRecord,
() -> _getAll(null, from, to, activityTypes, entityTypes));
() -> _getAll(institutionId, null, from, to, activityTypes, entityTypes));
}
@RequestMapping(path = "/page/{userId}", method = RequestMethod.GET)
public Page<UserActivityLog> getPageForUser(
@PathVariable final String userId,
@RequestParam(required = false) final Long from,
@RequestParam(required = false) final Long to,
@RequestParam(required = false) final String activityTypes,
@RequestParam(required = false) final String entityTypes,
@RequestParam(
name = UserActivityLog.FILTER_ATTR_INSTITUTION,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = UserActivityLog.FILTER_ATTR_FROM, required = false) final String from,
@RequestParam(name = UserActivityLog.FILTER_ATTR_TO, required = false) final String to,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
required = false) final String activityTypes,
@RequestParam(name = UserActivityLog.FILTER_ATTR_ENTITY_TYPES, required = false) final String entityTypes,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
checkBaseReadPrivilege();
checkBaseReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
UserRecordDynamicSqlSupport.userRecord,
() -> _getAll(userId, from, to, activityTypes, entityTypes));
}
private void checkBaseReadPrivilege() {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.USER_ACTIVITY_LOG,
PrivilegeType.READ_ONLY);
() -> _getAll(institutionId, userId, from, to, activityTypes, entityTypes));
}
private Collection<UserActivityLog> _getAll(
final Long institutionId,
final String userId,
final Long from,
final Long to,
final String from,
final String to,
final String activityTypes,
final String entityTypes) {
@ -142,24 +177,32 @@ public class UserActivityLogController {
Arrays.asList(StringUtils.split(entityTypes, Constants.LIST_SEPARATOR))))
: null;
if (_activityTypes != null || _entityTypes != null) {
final Predicate<UserActivityLogRecord> filter = (_activityTypes != null || _entityTypes != null)
? record -> {
if (_activityTypes != null && !_activityTypes.contains(record.getActivityType())) {
return false;
}
if (_entityTypes != null && !_entityTypes.contains(record.getEntityType())) {
return false;
}
return this.userActivityLogDAO.all(userId, from, to, record -> {
if (_activityTypes != null && !_activityTypes.contains(record.getActivityType())) {
return false;
}
if (_entityTypes != null && !_entityTypes.contains(record.getEntityType())) {
return false;
return true;
}
: record -> true;
return true;
}).getOrThrow();
return this.userActivityLogDAO.all(
institutionId,
userId,
Utils.toMilliSeconds(from),
Utils.toMilliSeconds(to),
filter).getOrThrow();
}
} else {
return this.userActivityLogDAO.all(userId, from, to, record -> true)
.getOrThrow();
}
private void checkBaseReadPrivilege(final Long institutionId) {
this.authorizationGrantService.checkPrivilege(
EntityType.USER_ACTIVITY_LOG,
PrivilegeType.READ_ONLY,
institutionId);
}
}

View file

@ -99,4 +99,12 @@ public abstract class AdministrationAPIIntegrationTest {
return obtainAccessToken("examAdmin1", "admin");
}
// protected static class TestHelper {
//
// private Supplier<String> accessTokenSuplier;
// private String query;
// private String endpoint;
// private Object
// }
}

View file

@ -21,6 +21,7 @@ import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Test;
import org.springframework.http.MediaType;
@ -28,7 +29,10 @@ import org.springframework.test.context.jdbc.Sql;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.APIMessage;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
@ -113,6 +117,15 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
contentAsString);
}
@Test
public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception {
final String token = getAdminInstitution1Access();
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isForbidden())
.andReturn().getResponse().getContentAsString();
}
@Test
public void getAllUserInfoNoFilter() throws Exception {
String token = getSebAdminAccess();
@ -126,34 +139,65 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
// expecting all users for a SEBAdmin except inactive.
assertNotNull(userInfos);
assertTrue(userInfos.size() == 7);
assertTrue(userInfos.size() == 3);
assertNotNull(getUserInfo("admin", userInfos));
assertNotNull(getUserInfo("inst1Admin", userInfos));
assertNotNull(getUserInfo("examSupporter", userInfos));
assertNotNull(getUserInfo("inst2Admin", userInfos));
assertNotNull(getUserInfo("examAdmin1", userInfos));
assertNotNull(getUserInfo("user1", userInfos));
assertNotNull(getUserInfo("deactivatedUser", userInfos));
token = getAdminInstitution1Access();
token = getAdminInstitution2Access();
userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT)
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserInfo>>() {
});
// expecting all users of institution 2 also inactive when active flag is not set
assertNotNull(userInfos);
assertTrue(userInfos.size() == 4);
assertNotNull(getUserInfo("inst2Admin", userInfos));
assertNotNull(getUserInfo("examAdmin1", userInfos));
assertNotNull(getUserInfo("deactivatedUser", userInfos));
assertNotNull(getUserInfo("user1", userInfos));
//.. and without inactive, if active flag is set to true
token = getAdminInstitution2Access();
userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2&active=true")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserInfo>>() {
});
// expecting all users of institution 1 for Institutional Admin of institution 1
assertNotNull(userInfos);
assertTrue(userInfos.size() == 3);
assertNotNull(getUserInfo("admin", userInfos));
assertNotNull(getUserInfo("inst1Admin", userInfos));
assertNotNull(getUserInfo("examSupporter", userInfos));
assertNotNull(getUserInfo("inst2Admin", userInfos));
assertNotNull(getUserInfo("examAdmin1", userInfos));
assertNotNull(getUserInfo("user1", userInfos));
//.. and only inactive, if active flag is set to false
token = getAdminInstitution2Access();
userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2&active=false")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserInfo>>() {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 1);
assertNotNull(getUserInfo("deactivatedUser", userInfos));
}
@Test
public void getPageNoFilterNoPageAttributes() throws Exception {
// expecting all user accounts of the institution of SEBAdmin
final String token = getSebAdminAccess();
final Page<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page")
@ -166,15 +210,18 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 1);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 7);
assertEquals("[user1, user2, user3, user4, user5, user6, user7]", getOrderedUUIDs(userInfos.content));
assertTrue(userInfos.content.size() == 3);
assertEquals("[user1, user2, user5]", getOrderedUUIDs(userInfos.content));
}
@Test
public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception {
public void getPageNoFilterNoPageAttributesFromOtherInstitution() throws Exception {
// expecting all user accounts of institution 2
final String token = getSebAdminAccess();
final Page<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page?sortOrder=DESCENDING")
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page?institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -184,8 +231,26 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 1);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 7);
assertEquals("[user7, user6, user5, user4, user3, user2, user1]", getOrderedUUIDs(userInfos.content));
assertTrue(userInfos.content.size() == 4);
assertEquals("[user3, user4, user6, user7]", getOrderedUUIDs(userInfos.content));
}
@Test
public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception {
final String token = getSebAdminAccess();
final Page<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page?sort_order=DESCENDING")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<Page<UserInfo>>() {
});
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 1);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 3);
assertEquals("[user5, user2, user1]", getOrderedUUIDs(userInfos.content));
}
@Test
@ -195,24 +260,25 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
// first page default sort order
Page<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page?pageNumber=1&pageSize=3")
.header("Authorization", "Bearer " + token))
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
+ "/page?page_number=1&page_size=3&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<Page<UserInfo>>() {
});
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 3);
assertTrue(userInfos.numberOfPages == 2);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 3);
assertEquals("[user1, user2, user3]", getOrderedUUIDs(userInfos.content));
assertEquals("[user3, user4, user6]", getOrderedUUIDs(userInfos.content));
// second page default sort order
userInfos = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
+ "/page?pageNumber=2&pageSize=3")
+ "/page?page_number=2&page_size=3&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -220,16 +286,17 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 3);
assertTrue(userInfos.numberOfPages == 2);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 3);
assertEquals("[user4, user5, user6]", getOrderedUUIDs(userInfos.content));
assertTrue(userInfos.pageSize == 1);
assertTrue(userInfos.content.size() == 1);
assertEquals("[user7]", getOrderedUUIDs(userInfos.content));
// third page default sort order
// invalid page number should refer to last page
userInfos = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
+ "/page?pageNumber=3&pageSize=3")
+ "/page?page_number=3&page_size=3&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -237,7 +304,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 3);
assertTrue(userInfos.numberOfPages == 2);
assertTrue(userInfos.pageNumber == 2);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 1);
assertEquals("[user7]", getOrderedUUIDs(userInfos.content));
@ -246,7 +314,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
userInfos = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
+ "/page?pageNumber=1&pageSize=3&sortOrder=DESCENDING")
+ "/page?page_number=1&page_size=3&sort_order=DESCENDING&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -254,10 +322,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.numberOfPages == 3);
assertTrue(userInfos.numberOfPages == 2);
assertNotNull(userInfos.content);
assertTrue(userInfos.content.size() == 3);
assertEquals("[user7, user6, user5]", getOrderedUUIDs(userInfos.content));
assertEquals("[user7, user6, user4]", getOrderedUUIDs(userInfos.content));
}
private String getOrderedUUIDs(final Collection<UserInfo> list) {
@ -280,15 +348,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 7);
assertNotNull(getUserInfo("deactivatedUser", userInfos));
assertTrue(userInfos.size() == 3);
}
@Test
public void getAllUserInfoWithOnlyActice() throws Exception {
public void getAllUserInfoWithOnlyActive() throws Exception {
final String token = getSebAdminAccess();
final List<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true")
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -296,14 +363,16 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 6);
assertTrue(userInfos.size() == 3);
assertNull(getUserInfo("deactivatedUser", userInfos));
}
@Test
public void getAllUserInfoOnlyInactive() throws Exception {
// expecting none for SEBAdmins institution
final String token = getSebAdminAccess();
final List<UserInfo> userInfos = this.jsonMapper.readValue(
List<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
@ -311,6 +380,18 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
new TypeReference<List<UserInfo>>() {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 0);
// expecting one for institution 2
userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserInfo>>() {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 1);
assertNotNull(getUserInfo("deactivatedUser", userInfos));
@ -328,8 +409,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(userInfos);
assertTrue(userInfos.size() == 2);
assertNotNull(getUserInfo("examAdmin1", userInfos));
assertTrue(userInfos.size() == 1);
assertNotNull(getUserInfo("examSupporter", userInfos));
}
@ -381,8 +461,9 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
// check user activity log for newly created user
final List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user1?activityTypes=CREATE")
.header("Authorization", "Bearer " + token))
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user1?activity_types=CREATE")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
@ -700,7 +781,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
@Test
public void deactivateUserAccount() throws Exception {
final long timeNow = System.currentTimeMillis();
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
// 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")
@ -709,16 +790,32 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
// With SEB Administrator it should work
final String sebAdminToken = getSebAdminAccess();
final UserInfo deactivatedUser = this.jsonMapper.readValue(
final EntityProcessingReport report = 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<EntityProcessingReport>() {
});
assertNotNull(report);
assertNotNull(report.source);
assertTrue(report.dependencies.isEmpty()); // TODO
assertTrue(report.errors.isEmpty());
assertTrue(report.source.size() == 1);
// get user and check activity
final EntityKey key = report.source.iterator().next();
final UserInfo user = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + key.modelId)
.header("Authorization", "Bearer " + sebAdminToken))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<UserInfo>() {
});
assertNotNull(deactivatedUser);
assertFalse(deactivatedUser.isActive());
assertNotNull(user);
assertFalse(user.isActive());
// check also user activity log
final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue(
@ -738,7 +835,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
@Test
public void activateUserAccount() throws Exception {
final long timeNow = System.currentTimeMillis();
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
// 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")
@ -747,16 +844,32 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
// With SEB Administrator it should work
final String sebAdminToken = getSebAdminAccess();
final UserInfo activatedUser = this.jsonMapper.readValue(
final EntityProcessingReport report = 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<EntityProcessingReport>() {
});
assertNotNull(report);
assertNotNull(report.source);
assertTrue(report.dependencies.isEmpty()); // TODO
assertTrue(report.errors.isEmpty());
assertTrue(report.source.size() == 1);
// get user and check activity
final EntityKey key = report.source.iterator().next();
final UserInfo user = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + key.modelId)
.header("Authorization", "Bearer " + sebAdminToken))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<UserInfo>() {
});
assertNotNull(activatedUser);
assertTrue(activatedUser.isActive());
assertNotNull(user);
assertTrue(user.isActive());
// check also user activity log
final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue(

View file

@ -8,18 +8,19 @@
package ch.ethz.seb.sebserver.webservice.integration.api;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.List;
import org.joda.time.DateTime;
import org.junit.Test;
import org.springframework.test.context.jdbc.Sql;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI;
@ -38,14 +39,15 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(logs);
assertTrue(5 == logs.size());
assertTrue(2 == logs.size());
}
@Test
public void getAllAsSEBAdminForUser() throws Exception {
final String token = getSebAdminAccess();
// for a user in another institution, the institution has to be defined
List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user4")
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user4?institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -55,6 +57,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
assertNotNull(logs);
assertTrue(2 == logs.size());
// for a user in the same institution no institution is needed
logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user2")
.header("Authorization", "Bearer " + token))
@ -69,47 +72,18 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
@Test
public void getAllAsSEBAdminInTimeRange() throws Exception {
final DateTime zeroDate = DateTime.parse("1970-01-01 00:00:00", Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
assertEquals("0", String.valueOf(zeroDate.getMillis()));
final String sec2 = zeroDate.plus(1000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
final String sec4 = zeroDate.plus(4000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
final String sec5 = zeroDate.plus(5000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
final String sec6 = zeroDate.plus(6000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
final String token = getSebAdminAccess();
List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?from=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(4 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?from=2&to=3")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(1 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?from=2&to=4")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(2 == logs.size());
}
@Test
public void getAllAsSEBAdminForActivityType() throws Exception {
final String token = getSebAdminAccess();
List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?activityTypes=CREATE")
.header("Authorization", "Bearer " + token))
this.mockMvc.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + sec2)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
@ -120,8 +94,8 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?activityTypes=CREATE,MODIFY")
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from="
+ sec2 + "&to=" + sec4)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -129,7 +103,77 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(logs);
assertTrue(5 == logs.size());
assertTrue(1 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + sec2
+ "&to=" + sec5)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(2 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + sec2
+ "&to=" + sec6)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(3 == logs.size());
}
@Test
public void getAllAsSEBAdminForActivityType() throws Exception {
final String token = getSebAdminAccess();
List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?activity_types=CREATE")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(1 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
+ "?activity_types=CREATE,MODIFY")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(2 == logs.size());
// for other institution (2)
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
+ "?institution=2&activity_types=CREATE,MODIFY")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(3 == logs.size());
}
@Test
@ -137,7 +181,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
final String token = getSebAdminAccess();
List<UserActivityLog> logs = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?entityTypes=INSTITUTION")
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?entity_types=INSTITUTION")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -151,7 +195,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
this.mockMvc
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
+ "?entityTypes=INSTITUTION,EXAM")
+ "?entity_types=INSTITUTION,EXAM")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
@ -159,7 +203,21 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest {
});
assertNotNull(logs);
assertTrue(5 == logs.size());
assertTrue(2 == logs.size());
logs = this.jsonMapper.readValue(
this.mockMvc
.perform(
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
+ "?entity_types=INSTITUTION,EXAM&institution=2")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(),
new TypeReference<List<UserActivityLog>>() {
});
assertNotNull(logs);
assertTrue(3 == logs.size());
}
@Test

View file

@ -24,10 +24,10 @@ INSERT INTO user_role VALUES
;
INSERT INTO user_activity_log VALUES
(1, 'user1', 1, 'MODIFY', 'INSTITUTION', '1', 'some message'),
(2, 'user2', 2, 'CREATE', 'EXAM', '1', 'some message'),
(3, 'user3', 3, 'CREATE', 'EXAM', '2', 'some message'),
(4, 'user4', 4, 'CREATE', 'EXAM', '33', 'some message'),
(5, 'user4', 5, 'MODIFY', 'EXAM', '33', 'some message')
(1, 'user1', 1000, 'MODIFY', 'INSTITUTION', '1', 'some message'),
(2, 'user2', 2000, 'CREATE', 'EXAM', '1', 'some message'),
(3, 'user3', 3000, 'CREATE', 'EXAM', '2', 'some message'),
(4, 'user4', 4000, 'CREATE', 'EXAM', '33', 'some message'),
(5, 'user4', 5000, 'MODIFY', 'EXAM', '33', 'some message')
;