diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ActivatableEntityDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ActivatableEntityDAO.java index 6729879f..8753288d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ActivatableEntityDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ActivatableEntityDAO.java @@ -11,8 +11,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import java.util.Collection; import java.util.Set; -import org.springframework.transaction.annotation.Transactional; - import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.ModelIdAware; @@ -23,13 +21,20 @@ import ch.ethz.seb.sebserver.gbl.util.Result; * @param the concrete Entity type */ public interface ActivatableEntityDAO extends EntityDAO { - /** Get a Collection of all active Entity instances for a concrete entity-domain. - * - * @return A Result refer to a Collection of all active Entity instances for a concrete entity-domain - * or refer to an error if happened */ - @Transactional(readOnly = true) - default Result> allActive() { - return all(i -> true, true); + Result> all(Long institutionId, Boolean active); + + default Result> allOfInstitution(final long institutionId, final Boolean active) { + return all(institutionId, active); + } + + @Override + default Result> all(final Long institutionId) { + return all(institutionId, true); + } + + @Override + default Result> allOfInstitution(final long institutionId) { + return all(institutionId, true); } /** Set all entities referred by the given Collection of EntityKey active / inactive diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java index b28b7bf2..3aa33f29 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java @@ -12,7 +12,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.springframework.transaction.annotation.Transactional; @@ -59,10 +58,11 @@ public interface EntityDAO { * If you need a fast filtering implement a specific filtering in SQL level * * @param predicate Predicate expecting instance of type specific entity type + * @param * @param active indicates if only active entities should be included (on SQL level). Can be null. * @return Result of Collection of Entity that matches a given predicate. Or an exception result on error * case */ - Result> all(Predicate predicate, Boolean active); + Result> all(Long institutionId); /** Use this to get a Collection of all entities of concrete type that matches a given predicate. * @@ -73,15 +73,8 @@ public interface EntityDAO { * @param predicate Predicate expecting instance of type specific entity type * @return Result of Collection of Entity that matches a given predicate. Or an exception result on error * case */ - default Result> all(final Predicate predicate) { - return all(predicate, null); - } - - /** Use this to get a Collection of all active entities of concrete type - * - * @return Result of Collection of all active entities or an exception result on error case */ - default Result> all() { - return all(entity -> true); + default Result> allOfInstitution(final long institutionId) { + return all(institutionId); } Result> loadEntities(Collection keys); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserDAO.java index a2deff8b..851ef5fb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserDAO.java @@ -9,9 +9,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import java.util.Collection; -import java.util.function.Predicate; - -import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.user.UserFilter; @@ -50,23 +47,7 @@ public interface UserDAO extends ActivatableEntityDAO, BulkAc * * @param filter The UserFilter instance containing all filter criteria * @return a Result of Collection of filtered UserInfo. Or an exception result on error case */ - @Transactional(readOnly = true) - default Result> all(final UserFilter filter) { - return all(filter, userInfo -> true); - } - - /** Use this to get a Collection of filtered UserInfo. The filter criteria - * from given UserFilter instance will be translated to SQL query and - * the filtering happens on data-base level - * - * Additional there can also given a predicate to filter UserInfo models after the SQL query - * - * NOTE: filter and predicate can be null. In this case(s) the default all methods are called - * - * @param filter The UserFilter instance containing all filter criteria - * @param predicate Predicate of UserInfo to filter the result of the SQL query afterwards - * @return a Result of Collection of filtered UserInfo. Or an exception result on error case */ - Result> all(UserFilter filter, Predicate predicate); + Result> allMatching(final UserFilter filter); /** Use this to get a Collection containing EntityKey's of all entities that belongs to a given User. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index f0d7c6d6..c430e302 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -82,7 +82,7 @@ public class ExamDAOImpl implements ExamDAO { @Override @Transactional(readOnly = true) - public Result> all(final Predicate predicate, final Boolean active) { + public Result> all(final Long institutionId, final Boolean active) { return Result.tryCatch(() -> { final QueryExpressionDSL>> example = this.examRecordMapper.selectByExample(); @@ -90,6 +90,9 @@ public class ExamDAOImpl implements ExamDAO { return (active != null) ? example .where( + ExamRecordDynamicSqlSupport.institutionId, + isEqualToWhenPresent(institutionId)) + .and( ExamRecordDynamicSqlSupport.active, isEqualToWhenPresent(BooleanUtils.toIntegerObject(active))) .build() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java index 789345af..2cc83f78 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java @@ -15,7 +15,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; @@ -63,7 +62,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { @Override @Transactional(readOnly = true) - public Result> all(final Predicate predicate, final Boolean active) { + public Result> all(final Long institutionId, final Boolean active) { return Result.tryCatch(() -> { final QueryExpressionDSL>> example = this.institutionRecordMapper.selectByExample(); @@ -71,6 +70,9 @@ public class InstitutionDAOImpl implements InstitutionDAO { final List records = (active != null) ? example .where( + InstitutionRecordDynamicSqlSupport.id, + isEqualToWhenPresent(institutionId)) + .and( InstitutionRecordDynamicSqlSupport.active, isEqualToWhenPresent(BooleanUtils.toIntegerObject(active))) .build() @@ -80,7 +82,6 @@ public class InstitutionDAOImpl implements InstitutionDAO { return records.stream() .map(InstitutionDAOImpl::toDomainModel) .flatMap(Result::skipOnError) - .filter(predicate) .collect(Collectors.toList()); }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java index 314b4883..74bf4c97 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java @@ -15,7 +15,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; @@ -62,7 +61,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { @Override @Transactional(readOnly = true) - public Result> all(final Predicate predicate, final Boolean active) { + public Result> all(final Long institutionId, final Boolean active) { return Result.tryCatch(() -> { final QueryExpressionDSL>> example = this.lmsSetupRecordMapper.selectByExample(); @@ -70,6 +69,9 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { final List records = (active != null) ? example .where( + LmsSetupRecordDynamicSqlSupport.institutionId, + isEqualToWhenPresent(institutionId)) + .and( LmsSetupRecordDynamicSqlSupport.active, isEqualToWhenPresent(BooleanUtils.toIntegerObject(active))) .build() @@ -79,7 +81,6 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { return records.stream() .map(LmsSetupDAOImpl::toDomainModel) .flatMap(Result::skipOnError) - .filter(predicate) .collect(Collectors.toList()); }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java index fe2eb704..e7441089 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java @@ -255,7 +255,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { @Override @Transactional(readOnly = true) - public Result> all(final Predicate predicate, final Boolean active) { + public Result> all(final Long institutionId) { return Result.tryCatch(() -> { // first check if there is a page limitation set. Otherwise set the default @@ -263,15 +263,32 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { this.paginationService.setDefaultLimitOfNotSet( UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord); - return this.userLogRecordMapper - .selectByExample() - .build() - .execute() - .stream() - .map(UserActivityLogDAOImpl::toDomainModel) - .flatMap(Result::skipOnError) - .filter(predicate) - .collect(Collectors.toList()); + if (institutionId == null) { + return this.userLogRecordMapper + .selectByExample() + .build() + .execute() + .stream() + .map(UserActivityLogDAOImpl::toDomainModel) + .flatMap(Result::skipOnError) + .collect(Collectors.toList()); + } else { + return this.userLogRecordMapper + .selectByExample() + .join(UserRecordDynamicSqlSupport.userRecord) + .on( + UserRecordDynamicSqlSupport.uuid, + SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid)) + .where( + UserRecordDynamicSqlSupport.institutionId, + SqlBuilder.isEqualTo(institutionId)) + .build() + .execute() + .stream() + .map(UserActivityLogDAOImpl::toDomainModel) + .flatMap(Result::skipOnError) + .collect(Collectors.toList()); + } }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java index b682b924..f197d0b0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java @@ -17,15 +17,12 @@ import java.util.List; import java.util.Locale; import java.util.Set; import java.util.UUID; -import java.util.function.Predicate; import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.apache.commons.lang3.BooleanUtils; import org.joda.time.DateTimeZone; -import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter; -import org.mybatis.dynamic.sql.select.QueryExpressionDSL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -60,7 +57,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO; public class UserDaoImpl implements UserDAO { private static final Logger log = LoggerFactory.getLogger(UserDaoImpl.class); - private static final UserFilter ALL_ACTIVE_ONLY_FILTER = new UserFilter(null, null, null, null, true, null); private final UserRecordMapper userRecordMapper; private final RoleRecordMapper roleRecordMapper; @@ -118,43 +114,35 @@ public class UserDaoImpl implements UserDAO { @Override @Transactional(readOnly = true) - public Result> allActive() { - return all(ALL_ACTIVE_ONLY_FILTER); - } - - @Override - @Transactional(readOnly = true) - public Result> all(final Predicate predicate, final Boolean active) { + public Result> all(final Long institutionId, final Boolean active) { return Result.tryCatch(() -> { - final QueryExpressionDSL>> example = - this.userRecordMapper.selectByExample(); - final List records = (active != null) - ? example + ? this.userRecordMapper.selectByExample() .where( + UserRecordDynamicSqlSupport.institutionId, + isEqualToWhenPresent(institutionId)) + .and( UserRecordDynamicSqlSupport.active, isEqualToWhenPresent(BooleanUtils.toIntegerObject(active))) .build() .execute() - : example.build().execute(); + : this.userRecordMapper.selectByExample() + .where( + UserRecordDynamicSqlSupport.institutionId, + isEqualToWhenPresent(institutionId)) + .build() + .execute(); return records.stream() .map(this::toDomainModel) .flatMap(Result::skipOnError) - .filter(predicate) .collect(Collectors.toList()); }); } @Override @Transactional(readOnly = true) - public Result> all(final UserFilter filter, final Predicate predicate) { - if (filter == null) { - return (predicate == null) - ? all() - : all(predicate); - } - + public Result> allMatching(final UserFilter filter) { return Result.tryCatch(() -> this.userRecordMapper.selectByExample().where( UserRecordDynamicSqlSupport.active, isEqualToWhenPresent(BooleanUtils.toIntegerObject(filter.active))) @@ -168,7 +156,6 @@ public class UserDaoImpl implements UserDAO { .stream() .map(this::toDomainModel) .flatMap(Result::skipOnError) - .filter(predicate) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java index 6aa0b676..54d3f91f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java @@ -8,35 +8,87 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; +import java.util.Collection; + import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import ch.ethz.seb.sebserver.gbl.model.Entity; 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.util.Result; +import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; 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.GrantEntity; 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.EntityDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; public abstract class ActivatableEntityController extends EntityController { + private final ActivatableEntityDAO activatableEntityDAO; + public ActivatableEntityController( final AuthorizationGrantService authorizationGrantService, final BulkActionService bulkActionService, - final EntityDAO entityDAO, + final ActivatableEntityDAO entityDAO, final UserActivityLogDAO userActivityLogDAO, final PaginationService paginationService) { super(authorizationGrantService, bulkActionService, entityDAO, userActivityLogDAO, paginationService); + this.activatableEntityDAO = entityDAO; + } + + @RequestMapping(path = "/active", method = RequestMethod.GET) + public Page allActive( + @RequestParam( + name = Entity.ATTR_INSTITUTION, + required = true, + defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, + @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) { + + checkReadPrivilege(institutionId); + return this.paginationService.getPage( + pageNumber, + pageSize, + sortBy, + sortOrder, + UserRecordDynamicSqlSupport.userRecord, + () -> this.activatableEntityDAO.all(institutionId, true).getOrThrow()); + } + + @RequestMapping(path = "/inactive", method = RequestMethod.GET) + public Page allInactive( + @RequestParam( + name = Entity.ATTR_INSTITUTION, + required = true, + defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, + @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) { + + checkReadPrivilege(institutionId); + return this.paginationService.getPage( + pageNumber, + pageSize, + sortBy, + sortOrder, + UserRecordDynamicSqlSupport.userRecord, + () -> this.activatableEntityDAO.all(institutionId, false).getOrThrow()); } @RequestMapping(path = "/{id}/activate", method = RequestMethod.POST) @@ -56,6 +108,11 @@ public abstract class ActivatableEntityController> getAll(final Long institutionId, final Boolean active) { + return this.activatableEntityDAO.all(institutionId, active); + } + private Result setActive(final String id, final boolean active) { final EntityType entityType = this.entityDAO.entityType(); final BulkAction bulkAction = new BulkAction( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java index 649bb1ea..3bda2418 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java @@ -27,9 +27,7 @@ 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.Page; import ch.ethz.seb.sebserver.gbl.util.Result; -import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; 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.GrantEntity; @@ -74,37 +72,8 @@ public abstract class EntityController allActive( - @RequestParam( - name = Entity.ATTR_INSTITUTION, - required = true, - defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, - @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) { - - checkReadPrivilege(institutionId); - return this.paginationService.getPage( - pageNumber, - pageSize, - sortBy, - sortOrder, - UserRecordDynamicSqlSupport.userRecord, - () -> this.entityDAO.all(entity -> true, true).getOrThrow()); - } - - @RequestMapping(path = "/all/in", method = RequestMethod.GET) - public Collection getForIds( - @RequestParam( - name = Entity.ATTR_INSTITUTION, - required = true, - defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, - @RequestParam(name = "ids", required = true) final String ids) { - - checkReadPrivilege(institutionId); - + @RequestMapping(path = "/in", method = RequestMethod.GET) + public Collection getForIds(@RequestParam(name = "ids", required = true) final String ids) { return Result.tryCatch(() -> { return Arrays.asList(StringUtils.split(ids, Constants.LIST_SEPARATOR_CHAR)) .stream() @@ -112,16 +81,24 @@ public abstract class EntityController this.authorizationGrantService.hasGrant(entity, PrivilegeType.READ_ONLY)) + .collect(Collectors.toList()); } @RequestMapping(path = "/names", method = RequestMethod.GET) public Collection getNames( + @RequestParam( + name = Entity.ATTR_INSTITUTION, + required = true, + defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, @RequestParam(name = Entity.ATTR_ACTIVE, required = false) final Boolean active) { - return this.entityDAO.all(entity -> true, true) + return getAll(institutionId, active) .getOrThrow() .stream() + .filter(entity -> this.authorizationGrantService.hasGrant(entity, PrivilegeType.READ_ONLY)) .map(Entity::toName) .collect(Collectors.toList()); } @@ -170,4 +147,8 @@ public abstract class EntityController> getAll(final Long institutionId, final Boolean active) { + return this.entityDAO.all(institutionId); + } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java index 3190869f..a8e3f58a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java @@ -13,22 +13,16 @@ 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; @@ -37,29 +31,21 @@ 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 { +public class ExamAdministrationController extends ActivatableEntityController { - 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, @@ -68,11 +54,8 @@ public class ExamAdministrationController { final PaginationService paginationService, final BulkActionService bulkActionService) { - this.authorizationGrantService = authorizationGrantService; - this.userActivityLogDAO = userActivityLogDAO; + super(authorizationGrantService, bulkActionService, examDAO, userActivityLogDAO, paginationService); this.examDAO = examDAO; - this.paginationService = paginationService; - this.bulkActionService = bulkActionService; } @InitBinder @@ -96,7 +79,7 @@ public class ExamAdministrationController { @RequestParam(name = Exam.FILTER_ATTR_TYPE, required = false) final ExamType type, @RequestParam(name = Exam.FILTER_ATTR_OWNER, required = false) final String owner) { - checkBaseReadPrivilege(institutionId); + checkReadPrivilege(institutionId); this.paginationService.setDefaultLimit(ExamRecordDynamicSqlSupport.examRecord); return getExams(institutionId, lmsSetupId, active, name, from, status, type, owner); @@ -120,7 +103,7 @@ public class ExamAdministrationController { @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); + checkReadPrivilege(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 @@ -166,46 +149,6 @@ public class ExamAdministrationController { } } - @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 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 getExams( final Long institutionId, final Long lmsSetupId, @@ -236,11 +179,4 @@ public class ExamAdministrationController { active).getOrThrow(); } - private void checkBaseReadPrivilege(final Long institutionId) { - this.authorizationGrantService.checkPrivilege( - EntityType.EXAM, - PrivilegeType.READ_ONLY, - institutionId); - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java index b79f6977..55999752 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java @@ -33,7 +33,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; public class InstitutionController extends ActivatableEntityController { private final InstitutionDAO institutionDAO; - private final AuthorizationGrantService authorizationGrantService; public InstitutionController( final InstitutionDAO institutionDAO, @@ -43,9 +42,7 @@ public class InstitutionController extends ActivatableEntityController true, active).getOrThrow(); + return this.institutionDAO.all(null, active).getOrThrow(); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java index a0463498..a398e96d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java @@ -10,10 +10,8 @@ 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; @@ -21,40 +19,30 @@ 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; 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.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.LmsSetup; 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.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.LmsSetupDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; -import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; @WebServiceProfile @RestController @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_LMS_SETUP) -public class LmsSetupController { +public class LmsSetupController extends ActivatableEntityController { private final LmsSetupDAO lmsSetupDAO; - private final AuthorizationGrantService authorizationGrantService; - private final UserActivityLogDAO userActivityLogDAO; - private final BulkActionService bulkActionService; private final LmsAPIService lmsAPIService; public LmsSetupController( @@ -62,12 +50,12 @@ public class LmsSetupController { final AuthorizationGrantService authorizationGrantService, final UserActivityLogDAO userActivityLogDAO, final BulkActionService bulkActionService, - final LmsAPIService lmsAPIService) { + final LmsAPIService lmsAPIService, + final PaginationService paginationService) { + + super(authorizationGrantService, bulkActionService, lmsSetupDAO, userActivityLogDAO, paginationService); this.lmsSetupDAO = lmsSetupDAO; - this.authorizationGrantService = authorizationGrantService; - this.userActivityLogDAO = userActivityLogDAO; - this.bulkActionService = bulkActionService; this.lmsAPIService = lmsAPIService; } @@ -95,34 +83,6 @@ public class LmsSetupController { .getOrThrow(); } - @RequestMapping(path = "/names", method = RequestMethod.GET) - public Collection getNames( - @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) - .collect(Collectors.toList()); - } - - @RequestMapping(path = "/{id}", method = RequestMethod.GET) - public LmsSetup getById(@PathVariable final Long id) { - return this.lmsSetupDAO - .byPK(id) - .flatMap(lmsSetup -> this.authorizationGrantService.checkGrantOnEntity( - lmsSetup, - PrivilegeType.READ_ONLY)) - .getOrThrow(); - } - @RequestMapping( path = "/create_seb_config/{id}", method = RequestMethod.GET, @@ -151,89 +111,4 @@ public class LmsSetupController { } } - @RequestMapping(path = "/create", method = RequestMethod.PUT) - public LmsSetup create(@Valid @RequestBody final LmsSetup lmsSetup) { - return save(lmsSetup, PrivilegeType.WRITE) - .getOrThrow(); - } - - @RequestMapping(path = "/save", method = RequestMethod.POST) - public LmsSetup save(@Valid @RequestBody final LmsSetup lmsSetup) { - return save(lmsSetup, PrivilegeType.MODIFY) - .getOrThrow(); - } - - @RequestMapping(path = "/{id}/activate", method = RequestMethod.POST) - public EntityProcessingReport activate(@PathVariable final Long id) { - return setActive(id, true); - } - - @RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST) - public EntityProcessingReport deactivate(@PathVariable final Long id) { - return setActive(id, false); - } - - @RequestMapping(path = "/{id}/delete", method = RequestMethod.DELETE) - public EntityProcessingReport deleteUser(@PathVariable final Long id) { - checkPrivilegeForInstitution(id, PrivilegeType.WRITE); - - return this.bulkActionService.createReport(new BulkAction( - Type.DEACTIVATE, - EntityType.LMS_SETUP, - new EntityKey(id, EntityType.LMS_SETUP))) - .getOrThrow(); - } - - @RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE) - public EntityProcessingReport hardDeleteUser(@PathVariable final Long id) { - checkPrivilegeForInstitution(id, PrivilegeType.WRITE); - - return this.bulkActionService.createReport(new BulkAction( - Type.HARD_DELETE, - EntityType.LMS_SETUP, - new EntityKey(id, EntityType.LMS_SETUP))) - .getOrThrow(); - } - - private void checkPrivilegeForInstitution(final Long lmsSetupId, final PrivilegeType type) { - this.authorizationGrantService.checkHasAnyPrivilege( - EntityType.LMS_SETUP, - type); - - this.lmsSetupDAO.byPK(lmsSetupId) - .flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity( - institution, - type)) - .getOrThrow(); - } - - private EntityProcessingReport setActive(final Long id, final boolean active) { - checkPrivilegeForInstitution(id, PrivilegeType.MODIFY); - - return this.bulkActionService.createReport(new BulkAction( - (active) ? Type.ACTIVATE : Type.DEACTIVATE, - EntityType.LMS_SETUP, - new EntityKey(id, EntityType.LMS_SETUP))) - .getOrThrow(); - } - - private Result save(final LmsSetup lmsSetup, final PrivilegeType privilegeType) { - - final ActivityType activityType = (lmsSetup.id == null) - ? ActivityType.CREATE - : ActivityType.MODIFY; - - return this.authorizationGrantService - .checkGrantOnEntity(lmsSetup, privilegeType) - .flatMap(this.lmsSetupDAO::save) - .flatMap(exam -> this.userActivityLogDAO.log(activityType, exam)); - } - - private void checkReadPrivilege(final Long institutionId) { - this.authorizationGrantService.checkPrivilege( - EntityType.LMS_SETUP, - PrivilegeType.READ_ONLY, - institutionId); - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 3701d304..129073a3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -9,6 +9,8 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.springframework.context.ApplicationEventPublisher; import org.springframework.web.bind.WebDataBinder; @@ -28,6 +30,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; 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.GrantEntity; 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.BulkActionService; @@ -41,8 +44,6 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint; public class UserAccountController extends ActivatableEntityController { private final UserDAO userDao; - private final AuthorizationGrantService authorizationGrantService; - private final PaginationService paginationService; private final ApplicationEventPublisher applicationEventPublisher; public UserAccountController( @@ -55,8 +56,6 @@ public class UserAccountController extends ActivatableEntityController grantFilter = this.authorizationGrantService.getGrantFilter( + EntityType.USER, + PrivilegeType.READ_ONLY); + + return this.userDao + .allMatching(userFilter) + .getOrThrow() + .stream() + .filter(grantFilter) + .collect(Collectors.toList()); } } diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/AdministrationAPIIntegrationTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/AdministrationAPIIntegrationTest.java index 23276939..ba5beb27 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/AdministrationAPIIntegrationTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/AdministrationAPIIntegrationTest.java @@ -9,10 +9,13 @@ package ch.ethz.seb.sebserver.webservice.integration.api; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.HashMap; +import java.util.Map; + import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -20,16 +23,22 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.json.JacksonJsonParser; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.security.web.FilterChainProxy; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.context.WebApplicationContext; +import com.fasterxml.jackson.core.type.TypeReference; + import ch.ethz.seb.sebserver.SEBServer; import ch.ethz.seb.sebserver.gbl.JSONMapper; @@ -99,12 +108,110 @@ public abstract class AdministrationAPIIntegrationTest { return obtainAccessToken("examAdmin1", "admin"); } -// protected static class TestHelper { -// -// private Supplier accessTokenSuplier; -// private String query; -// private String endpoint; -// private Object -// } + protected class RestAPITestHelper { + + private String path = ""; + private final Map queryAttrs = new HashMap<>(); + private String accessToken; + private HttpStatus expectedStatus; + private HttpMethod httpMethod = HttpMethod.GET; + + public RestAPITestHelper withAccessToken(final String accessToken) { + this.accessToken = accessToken; + return this; + } + + public RestAPITestHelper withPath(final String path) { + this.path = this.path + path; + return this; + } + + public RestAPITestHelper withAttribute(final String name, final String value) { + this.queryAttrs.put(name, value); + return this; + } + + public RestAPITestHelper withExpectedStatus(final HttpStatus expectedStatus) { + this.expectedStatus = expectedStatus; + return this; + } + + public RestAPITestHelper withMethod(final HttpMethod httpMethod) { + this.httpMethod = httpMethod; + return this; + } + + public String getAsString() throws Exception { + final ResultActions action = AdministrationAPIIntegrationTest.this.mockMvc + .perform(requestBuilder()); + if (this.expectedStatus != null) { + action.andExpect(status().is(this.expectedStatus.value())); + } + + return action + .andReturn() + .getResponse() + .getContentAsString(); + } + + public T getAsObject(final TypeReference ref) throws Exception { + final ResultActions action = AdministrationAPIIntegrationTest.this.mockMvc + .perform(requestBuilder()); + if (this.expectedStatus != null) { + action.andExpect(status().is(this.expectedStatus.value())); + } + + return AdministrationAPIIntegrationTest.this.jsonMapper.readValue( + action + .andReturn() + .getResponse() + .getContentAsString(), + ref); + } + + private RequestBuilder requestBuilder() { + MockHttpServletRequestBuilder builder = get(getFullPath()); + switch (this.httpMethod) { + case GET: + builder = get(getFullPath()); + break; + case POST: + builder = post(getFullPath()); + break; + case PUT: + builder = put(getFullPath()); + break; + case DELETE: + builder = delete(getFullPath()); + break; + case PATCH: + builder = patch(getFullPath()); + break; + default: + get(getFullPath()); + break; + } + return builder.header("Authorization", "Bearer " + this.accessToken); + } + + private String getFullPath() { + final StringBuilder sb = new StringBuilder(); + sb.append(AdministrationAPIIntegrationTest.this.endpoint); + sb.append(this.path); + if (!this.queryAttrs.isEmpty()) { + sb.append("?"); + this.queryAttrs.entrySet() + .stream() + .reduce( + sb, + (buffer, entry) -> buffer.append(entry.getKey()).append("=").append(entry.getValue()) + .append("&"), + (sb1, sb2) -> sb1.append(sb2)); + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + } + + } } diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/UserAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/UserAPITest.java index ae16bd51..a1f14f9e 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/UserAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/UserAPITest.java @@ -24,6 +24,7 @@ import java.util.stream.Stream; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Test; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.context.jdbc.Sql; @@ -32,6 +33,7 @@ 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.EntityKeyAndName; 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; @@ -46,11 +48,11 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { @Test public void getMyUserInfo() throws Exception { - String sebAdminAccessToken = getSebAdminAccess(); - String contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") - .header("Authorization", "Bearer " + sebAdminAccessToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); + String contentAsString = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me") + .withExpectedStatus(HttpStatus.OK) + .getAsString(); assertEquals( "{\"uuid\":\"user1\"," @@ -64,11 +66,11 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { + "\"userRoles\":[\"SEB_SERVER_ADMIN\"]}", contentAsString); - sebAdminAccessToken = getAdminInstitution1Access(); - contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") - .header("Authorization", "Bearer " + sebAdminAccessToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); + contentAsString = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me") + .withExpectedStatus(HttpStatus.OK) + .getAsString(); assertEquals( "{\"uuid\":\"user2\"," @@ -119,22 +121,20 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { @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(); + new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2") + .withExpectedStatus(HttpStatus.FORBIDDEN) + .getAsString(); } @Test public void getAllUserInfoNoFilter() throws Exception { - String token = getSebAdminAccess(); - List userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { + List userInfos = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { }); // expecting all users for a SEBAdmin except inactive. @@ -144,13 +144,12 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { assertNotNull(getUserInfo("inst1Admin", userInfos)); assertNotNull(getUserInfo("examSupporter", userInfos)); - token = getAdminInstitution2Access(); - userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2") - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) + .withAttribute("institution", "2") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { }); // expecting all users of institution 2 also inactive when active flag is not set @@ -162,13 +161,13 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { 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>() { + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) + .withAttribute("institution", "2") + .withAttribute("active", "true") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { }); assertNotNull(userInfos); @@ -178,13 +177,13 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { 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>() { + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) + .withAttribute("institution", "2") + .withAttribute("active", "false") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { }); assertNotNull(userInfos); @@ -887,6 +886,152 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { assertEquals("user6", userLog.entityId); } + @Test + public void testGeneralAllActiveInactiveEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // all active for the own institution + Page usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/active") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 3); + assertEquals("[user1, user2, user5]", getOrderedUUIDs(usersPage.content)); + + // all inactive of the own institution + usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/inactive") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 0); + assertEquals("[]", getOrderedUUIDs(usersPage.content)); + + // all active of institution 2 + usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/active?institution=2") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 3); + assertEquals("[user3, user4, user7]", getOrderedUUIDs(usersPage.content)); + + // all inactive of institution 2 + usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/inactive?institution=2") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 1); + assertEquals("[user6]", getOrderedUUIDs(usersPage.content)); + } + + @Test + public void testGeneralInEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // for SEB Admin it should be possible to get from different institutions + Collection users = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/in?ids=user1,user2,user6,user7") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(users); + assertTrue(users.size() == 4); + assertEquals("[user1, user2, user6, user7]", getOrderedUUIDs(users)); + + // for an institutional admin it should only be possible to get from own institution + final String instAdminToken = getAdminInstitution2Access(); + users = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/in?ids=user1,user2,user6,user7") + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(users); + assertTrue(users.size() == 2); + assertEquals("[user6, user7]", getOrderedUUIDs(users)); + } + + @Test + public void testGeneralNamesEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // for SEB Admin + Collection names = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 3); + assertEquals("[EntityIdAndName [entityType=USER, id=user1, name=SEBAdmin], " + + "EntityIdAndName [entityType=USER, id=user2, name=Institutional1 Admin], " + + "EntityIdAndName [entityType=USER, id=user5, name=Exam Supporter]]", names.toString()); + + // for an institutional admin 2 + final String instAdminToken = getAdminInstitution2Access(); + names = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 4); + assertEquals("[EntityIdAndName [entityType=USER, id=user3, name=Institutional2 Admin], " + + "EntityIdAndName [entityType=USER, id=user4, name=ExamAdmin1], " + + "EntityIdAndName [entityType=USER, id=user6, name=Deactivated], " + + "EntityIdAndName [entityType=USER, id=user7, name=User]]", names.toString()); + + // for an institutional admin 2 only active + names = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names?active=true") + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 3); + assertEquals("[EntityIdAndName [entityType=USER, id=user3, name=Institutional2 Admin], " + + "EntityIdAndName [entityType=USER, id=user4, name=ExamAdmin1], " + + "EntityIdAndName [entityType=USER, id=user7, name=User]]", names.toString()); + } + private UserInfo getUserInfo(final String name, final Collection infos) { try { return infos