created controller abstraction for Entity and ActivatableEntity
This commit is contained in:
		
							parent
							
								
									2f8b796b86
								
							
						
					
					
						commit
						ca20785400
					
				
					 39 changed files with 1376 additions and 572 deletions
				
			
		|  | @ -10,6 +10,9 @@ package ch.ethz.seb.sebserver.gbl.model; | ||||||
| 
 | 
 | ||||||
| public interface Entity extends ModelIdAware { | public interface Entity extends ModelIdAware { | ||||||
| 
 | 
 | ||||||
|  |     public static final String ATTR_ID = "id"; | ||||||
|  |     public static final String ATTR_INSTITUTION = "institution"; | ||||||
|  | 
 | ||||||
|     EntityType entityType(); |     EntityType entityType(); | ||||||
| 
 | 
 | ||||||
|     String getName(); |     String getName(); | ||||||
|  |  | ||||||
|  | @ -8,35 +8,40 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gbl.model; | 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 class EntityKey { | ||||||
| 
 | 
 | ||||||
|     public final String entityId; |     @JsonProperty(value = "modelId", required = true) | ||||||
|  |     public final String modelId; | ||||||
|  |     @JsonProperty(value = "entityType", required = true) | ||||||
|     public final EntityType entityType; |     public final EntityType entityType; | ||||||
|  |     @JsonIgnore | ||||||
|     public final boolean isIdPK; |     public final boolean isIdPK; | ||||||
| 
 | 
 | ||||||
|  |     @JsonCreator | ||||||
|     public EntityKey( |     public EntityKey( | ||||||
|             @NotNull final Long entityId, |             @JsonProperty(value = "modelId", required = true) final String modelId, | ||||||
|             @NotNull final EntityType entityType) { |             @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.entityType = entityType; | ||||||
|         this.isIdPK = true; |         this.isIdPK = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public EntityKey( |     public String getModelId() { | ||||||
|             @NotNull final String entityId, |         return this.modelId; | ||||||
|             @NotNull final EntityType entityType, |  | ||||||
|             final boolean isIdPK) { |  | ||||||
| 
 |  | ||||||
|         this.entityId = entityId; |  | ||||||
|         this.entityType = entityType; |  | ||||||
|         this.isIdPK = isIdPK; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public String getEntityId() { |  | ||||||
|         return this.entityId; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public EntityType getEntityType() { |     public EntityType getEntityType() { | ||||||
|  | @ -47,8 +52,8 @@ public class EntityKey { | ||||||
|     public int hashCode() { |     public int hashCode() { | ||||||
|         final int prime = 31; |         final int prime = 31; | ||||||
|         int result = 1; |         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.entityType == null) ? 0 : this.entityType.hashCode()); | ||||||
|  |         result = prime * result + ((this.modelId == null) ? 0 : this.modelId.hashCode()); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -61,19 +66,19 @@ public class EntityKey { | ||||||
|         if (getClass() != obj.getClass()) |         if (getClass() != obj.getClass()) | ||||||
|             return false; |             return false; | ||||||
|         final EntityKey other = (EntityKey) obj; |         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) |         if (this.entityType != other.entityType) | ||||||
|             return false; |             return false; | ||||||
|  |         if (this.modelId == null) { | ||||||
|  |             if (other.modelId != null) | ||||||
|  |                 return false; | ||||||
|  |         } else if (!this.modelId.equals(other.modelId)) | ||||||
|  |             return false; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public String toString() { |     public String toString() { | ||||||
|         return "EntityKey [entityId=" + this.entityId + ", entityType=" + this.entityType + "]"; |         return "EntityKey [modelId=" + this.modelId + ", entityType=" + this.entityType + "]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|     @JsonProperty(value = "entityType", required = true) |     @JsonProperty(value = "entityType", required = true) | ||||||
|     public final EntityType entityType; |     public final EntityType entityType; | ||||||
|     @JsonProperty(value = Domain.ATTR_ID, required = true) |     @JsonProperty(value = Domain.ATTR_ID, required = true) | ||||||
|     public final String id; |     public final String modelId; | ||||||
|     @JsonProperty(value = "name", required = true) |     @JsonProperty(value = "name", required = true) | ||||||
|     public final String name; |     public final String name; | ||||||
| 
 | 
 | ||||||
|  | @ -30,14 +30,14 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|             @JsonProperty(value = "name", required = true) final String name) { |             @JsonProperty(value = "name", required = true) final String name) { | ||||||
| 
 | 
 | ||||||
|         this.entityType = entityType; |         this.entityType = entityType; | ||||||
|         this.id = id; |         this.modelId = id; | ||||||
|         this.name = name; |         this.name = name; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public EntityKeyAndName(final EntityKey entityKey, final String name) { |     public EntityKeyAndName(final EntityKey entityKey, final String name) { | ||||||
| 
 | 
 | ||||||
|         this.entityType = entityKey.entityType; |         this.entityType = entityKey.entityType; | ||||||
|         this.id = entityKey.entityId; |         this.modelId = entityKey.modelId; | ||||||
|         this.name = name; |         this.name = name; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -45,10 +45,6 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|         return this.entityType; |         return this.entityType; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public String getId() { |  | ||||||
|         return this.id; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |     @Override | ||||||
|     public String getName() { |     public String getName() { | ||||||
|         return this.name; |         return this.name; | ||||||
|  | @ -57,7 +53,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|     @Override |     @Override | ||||||
|     @JsonIgnore |     @JsonIgnore | ||||||
|     public String getModelId() { |     public String getModelId() { | ||||||
|         return this.id; |         return this.modelId; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -65,7 +61,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|         final int prime = 31; |         final int prime = 31; | ||||||
|         int result = 1; |         int result = 1; | ||||||
|         result = prime * result + ((this.entityType == null) ? 0 : this.entityType.hashCode()); |         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()); |         result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  | @ -81,10 +77,10 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|         final EntityKeyAndName other = (EntityKeyAndName) obj; |         final EntityKeyAndName other = (EntityKeyAndName) obj; | ||||||
|         if (this.entityType != other.entityType) |         if (this.entityType != other.entityType) | ||||||
|             return false; |             return false; | ||||||
|         if (this.id == null) { |         if (this.modelId == null) { | ||||||
|             if (other.id != null) |             if (other.modelId != null) | ||||||
|                 return false; |                 return false; | ||||||
|         } else if (!this.id.equals(other.id)) |         } else if (!this.modelId.equals(other.modelId)) | ||||||
|             return false; |             return false; | ||||||
|         if (this.name == null) { |         if (this.name == null) { | ||||||
|             if (other.name != null) |             if (other.name != null) | ||||||
|  | @ -96,7 +92,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public String toString() { |     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 + "]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,30 +9,46 @@ | ||||||
| package ch.ethz.seb.sebserver.gbl.model; | package ch.ethz.seb.sebserver.gbl.model; | ||||||
| 
 | 
 | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.Map; |  | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.annotation.JsonCreator; | import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||||
|  | 
 | ||||||
| public class EntityProcessingReport { | public class EntityProcessingReport { | ||||||
| 
 | 
 | ||||||
|     @JsonProperty(value = "source", required = true) |     @JsonProperty(value = "source", required = true) | ||||||
|     public final Collection<Entity> source; |     public final Collection<EntityKey> source; | ||||||
|     @JsonProperty(value = "dependencies", required = true) |     @JsonProperty(value = "dependencies", required = true) | ||||||
|     public final Collection<EntityKeyAndName> dependencies; |     public final Collection<EntityKey> dependencies; | ||||||
|     @JsonProperty(value = "errors", required = true) |     @JsonProperty(value = "errors", required = true) | ||||||
|     public final Map<EntityKeyAndName, String> errors; |     public final Collection<ErrorEntry> errors; | ||||||
| 
 | 
 | ||||||
|     @JsonCreator |     @JsonCreator | ||||||
|     public EntityProcessingReport( |     public EntityProcessingReport( | ||||||
|             @JsonProperty(value = "source", required = true) final Collection<Entity> source, |             @JsonProperty(value = "source", required = true) final Collection<EntityKey> source, | ||||||
|             @JsonProperty(value = "dependencies", required = true) final Collection<EntityKeyAndName> dependencies, |             @JsonProperty(value = "dependencies", required = true) final Collection<EntityKey> dependencies, | ||||||
|             @JsonProperty(value = "errors", required = true) final Map<EntityKeyAndName, String> errors) { |             @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); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,11 +22,11 @@ public final class Page<T> { | ||||||
|         DESCENDING |         DESCENDING | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static final String ATTR_NUMBER_OF_PAGES = "numberOfPages"; |     public static final String ATTR_NUMBER_OF_PAGES = "number_of_pages"; | ||||||
|     public static final String ATTR_PAGE_NUMBER = "pageNumber"; |     public static final String ATTR_PAGE_NUMBER = "page_number"; | ||||||
|     public static final String ATTR_PAGE_SIZE = "pageSize"; |     public static final String ATTR_PAGE_SIZE = "page_size"; | ||||||
|     public static final String ATTR_SORT_BY = "sortBy"; |     public static final String ATTR_SORT_BY = "sort_by"; | ||||||
|     public static final String ATTR_SORT_ORDER = "sortOrder"; |     public static final String ATTR_SORT_ORDER = "sort_order"; | ||||||
|     public static final String ATTR_CONTENT = "content"; |     public static final String ATTR_CONTENT = "content"; | ||||||
| 
 | 
 | ||||||
|     @JsonProperty(ATTR_NUMBER_OF_PAGES) |     @JsonProperty(ATTR_NUMBER_OF_PAGES) | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; | ||||||
| 
 | 
 | ||||||
| public final class Exam implements GrantEntity, Activatable { | 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_LMS_SETUP = "lms_setup"; | ||||||
|     public static final String FILTER_ATTR_NAME = "name_like"; |     public static final String FILTER_ATTR_NAME = "name_like"; | ||||||
|     public static final String FILTER_ATTR_STATUS = "status"; |     public static final String FILTER_ATTR_STATUS = "status"; | ||||||
|  |  | ||||||
|  | @ -22,11 +22,6 @@ public final class QuizData { | ||||||
|     public static final String FILTER_ATTR_NAME = "name_like"; |     public static final String FILTER_ATTR_NAME = "name_like"; | ||||||
|     public static final String FILTER_ATTR_START_TIME = "start_timestamp"; |     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_ID = "quiz_id"; | ||||||
|     public static final String QUIZ_ATTR_NAME = "quiz_name"; |     public static final String QUIZ_ATTR_NAME = "quiz_name"; | ||||||
|     public static final String QUIZ_ATTR_DESCRIPTION = "quiz_description"; |     public static final String QUIZ_ATTR_DESCRIPTION = "quiz_description"; | ||||||
|  |  | ||||||
|  | @ -19,6 +19,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.Acti | ||||||
| 
 | 
 | ||||||
| public class UserActivityLog implements Entity { | 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 |     @JsonIgnore | ||||||
|     public final Long id; |     public final Long id; | ||||||
|     @JsonProperty(USER_ACTIVITY_LOG.ATTR_USER_UUID) |     @JsonProperty(USER_ACTIVITY_LOG.ATTR_USER_UUID) | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ import java.util.Map; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.joda.time.DateTime; | import org.joda.time.DateTime; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
|  | @ -105,4 +106,24 @@ public final class Utils { | ||||||
|         return map; |         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(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | 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.UserActivityLogRecordDynamicSqlSupport; | ||||||
| import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; | import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; | ||||||
| 
 | 
 | ||||||
|  | @ -50,6 +51,25 @@ public class PaginationService { | ||||||
|         initSortColumnMapping(); |         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) { |     public void setDefaultLimitOfNotSet(final SqlTable table) { | ||||||
|         if (PageHelper.getLocalPage() != null) { |         if (PageHelper.getLocalPage() != null) { | ||||||
|             return; |             return; | ||||||
|  | @ -69,6 +89,20 @@ public class PaginationService { | ||||||
|         setPagination(1, this.maxPageSize, sortBy, sortOrder, table); |         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( |     public com.github.pagehelper.Page<Object> setPagination( | ||||||
|             final Integer pageNumber, |             final Integer pageNumber, | ||||||
|             final Integer pageSize, |             final Integer pageSize, | ||||||
|  | @ -76,18 +110,8 @@ public class PaginationService { | ||||||
|             final Page.SortOrder sortOrder, |             final Page.SortOrder sortOrder, | ||||||
|             final SqlTable table) { |             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 = |         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); |         final String sortColumnName = verifySortColumnName(sortBy, table); | ||||||
|         if (StringUtils.isNoneBlank(sortColumnName)) { |         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 com.github.pagehelper.Page<Object> page = setPagination(pageNumber, pageSize, sortBy, sortOrder, table); | ||||||
|         final Collection<T> pageList = delegate.get(); |         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) { |     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? |     // TODO is it possible to generate this within MyBatis generator? | ||||||
|     private void initSortColumnMapping() { |     private void initSortColumnMapping() { | ||||||
|  | 
 | ||||||
|         // User Table |         // User Table | ||||||
|         final Map<String, String> userTableMap = new HashMap<>(); |         final Map<String, String> userTableMap = new HashMap<>(); | ||||||
|         userTableMap.put(Domain.USER.ATTR_NAME, UserRecordDynamicSqlSupport.name.name()); |         userTableMap.put(Domain.USER.ATTR_NAME, UserRecordDynamicSqlSupport.name.name()); | ||||||
|  | @ -163,6 +188,21 @@ public class PaginationService { | ||||||
|                 UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.name(), |                 UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.name(), | ||||||
|                 Domain.USER_ACTIVITY_LOG.ATTR_ID); |                 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()); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| public interface AuthorizationGrantService { | public interface AuthorizationGrantService { | ||||||
| 
 | 
 | ||||||
|     /** Gets the UserService that is bundled within the AuthorizationGrantService |     /** Gets the UserService that is bundled within the AuthorizationGrantService | ||||||
|      *  |      * | ||||||
|      * @return the UserService that is bundled within the AuthorizationGrantService */ |      * @return the UserService that is bundled within the AuthorizationGrantService */ | ||||||
|     UserService getUserService(); |     UserService getUserService(); | ||||||
| 
 | 
 | ||||||
|  | @ -33,6 +33,10 @@ public interface AuthorizationGrantService { | ||||||
|      * @param privilegeType the PrivilegeType to check on EntityType */ |      * @param privilegeType the PrivilegeType to check on EntityType */ | ||||||
|     void checkHasAnyPrivilege(EntityType entityType, PrivilegeType privilegeType); |     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 |     /** Check if current user has grant on a given GrantEntity instance for specified PrivilegeType | ||||||
|      * |      * | ||||||
|      * @param entity The GrantEntity to check specified PrivilegeType for |      * @param entity The GrantEntity to check specified PrivilegeType for | ||||||
|  |  | ||||||
|  | @ -120,49 +120,86 @@ public class AuthorizationGrantServiceImpl implements AuthorizationGrantService | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @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(); |         final SEBServerUser currentUser = this.userService.getCurrentUser(); | ||||||
|         if (hasBasePrivilege(entityType, grantType, currentUser) || |         if (hasBasePrivilege(entityType, privilegeType, currentUser) || | ||||||
|                 hasInstitutionalPrivilege(entityType, grantType, currentUser)) { |                 hasInstitutionalPrivilege(entityType, privilegeType, currentUser)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         throw new PermissionDeniedException(entityType, grantType, currentUser.getUserInfo().uuid); |         throw new PermissionDeniedException(entityType, privilegeType, currentUser.getUserInfo().uuid); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @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(); |         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); |             return Result.of(entity); | ||||||
|         } else { |         } else { | ||||||
|             return Result.ofError(new PermissionDeniedException(entity, grantType, currentUser.getUserInfo().uuid)); |             return Result.ofError(new PermissionDeniedException(entity, privilegeType, currentUser.getUserInfo().uuid)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hasBasePrivilege(final EntityType entityType, final PrivilegeType grantType) { |     public boolean hasBasePrivilege(final EntityType entityType, final PrivilegeType privilegeType) { | ||||||
|         return hasBasePrivilege(entityType, grantType, this.userService.getCurrentUser()); |         return hasBasePrivilege(entityType, privilegeType, this.userService.getCurrentUser()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hasBasePrivilege( |     public boolean hasBasePrivilege( | ||||||
|             final EntityType entityType, |             final EntityType entityType, | ||||||
|             final PrivilegeType grantType, |             final PrivilegeType privilegeType, | ||||||
|             final Principal principal) { |             final Principal principal) { | ||||||
| 
 | 
 | ||||||
|         return hasBasePrivilege(entityType, grantType, this.userService.extractFromPrincipal(principal)); |         return hasBasePrivilege(entityType, privilegeType, this.userService.extractFromPrincipal(principal)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean hasBasePrivilege( |     private boolean hasBasePrivilege( | ||||||
|             final EntityType entityType, |             final EntityType entityType, | ||||||
|             final PrivilegeType grantType, |             final PrivilegeType privilegeType, | ||||||
|             final SEBServerUser user) { |             final SEBServerUser user) { | ||||||
| 
 | 
 | ||||||
|         for (final UserRole role : user.getUserRoles()) { |         for (final UserRole role : user.getUserRoles()) { | ||||||
|             final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role)); |             final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role)); | ||||||
|             if (roleTypeGrant != null && roleTypeGrant.hasBasePrivilege(grantType)) { |             if (roleTypeGrant != null && roleTypeGrant.hasBasePrivilege(privilegeType)) { | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -171,27 +208,36 @@ public class AuthorizationGrantServiceImpl implements AuthorizationGrantService | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hasInstitutionalPrivilege(final EntityType entityType, final PrivilegeType grantType) { |     public boolean hasInstitutionalPrivilege( | ||||||
|         return hasInstitutionalPrivilege(entityType, grantType, this.userService.getCurrentUser()); |             final EntityType entityType, | ||||||
|  |             final PrivilegeType privilegeType) { | ||||||
|  | 
 | ||||||
|  |         return hasInstitutionalPrivilege( | ||||||
|  |                 entityType, | ||||||
|  |                 privilegeType, | ||||||
|  |                 this.userService.getCurrentUser()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hasInstitutionalPrivilege( |     public boolean hasInstitutionalPrivilege( | ||||||
|             final EntityType entityType, |             final EntityType entityType, | ||||||
|             final PrivilegeType grantType, |             final PrivilegeType privilegeType, | ||||||
|             final Principal principal) { |             final Principal principal) { | ||||||
| 
 | 
 | ||||||
|         return hasInstitutionalPrivilege(entityType, grantType, this.userService.extractFromPrincipal(principal)); |         return hasInstitutionalPrivilege( | ||||||
|  |                 entityType, | ||||||
|  |                 privilegeType, | ||||||
|  |                 this.userService.extractFromPrincipal(principal)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean hasInstitutionalPrivilege( |     private boolean hasInstitutionalPrivilege( | ||||||
|             final EntityType entityType, |             final EntityType entityType, | ||||||
|             final PrivilegeType grantType, |             final PrivilegeType privilegeType, | ||||||
|             final SEBServerUser user) { |             final SEBServerUser user) { | ||||||
| 
 | 
 | ||||||
|         for (final UserRole role : user.getUserRoles()) { |         for (final UserRole role : user.getUserRoles()) { | ||||||
|             final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role)); |             final Privilege roleTypeGrant = this.grants.get(new RoleTypeKey(entityType, role)); | ||||||
|             if (roleTypeGrant != null && roleTypeGrant.hasInstitutionalPrivilege(grantType)) { |             if (roleTypeGrant != null && roleTypeGrant.hasInstitutionalPrivilege(privilegeType)) { | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -10,9 +10,13 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.authorization; | ||||||
| 
 | 
 | ||||||
| import java.security.Principal; | import java.security.Principal; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.web.bind.WebDataBinder; | ||||||
|  | 
 | ||||||
| /** A service to get the authenticated user from current request */ | /** A service to get the authenticated user from current request */ | ||||||
| public interface UserService { | 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. |     /** Use this to get the current User within a request-response thread cycle. | ||||||
|      * |      * | ||||||
|      * @return the SEBServerUser instance of the current request |      * @return the SEBServerUser instance of the current request | ||||||
|  | @ -46,4 +50,6 @@ public interface UserService { | ||||||
|      * @return an overall super user with all rights */ |      * @return an overall super user with all rights */ | ||||||
|     SEBServerUser getSuperUser(); |     SEBServerUser getSuperUser(); | ||||||
| 
 | 
 | ||||||
|  |     void addUsersInstitutionDefaultPropertySupport(final WebDataBinder binder); | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.authorization; | package ch.ethz.seb.sebserver.webservice.servicelayer.authorization; | ||||||
| 
 | 
 | ||||||
|  | import java.beans.PropertyEditorSupport; | ||||||
| import java.security.Principal; | import java.security.Principal; | ||||||
| import java.util.Collection; | 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.security.oauth2.provider.OAuth2Authentication; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| import org.springframework.stereotype.Service; | 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.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
|  | @ -78,6 +80,22 @@ public class UserServiceImpl implements UserService { | ||||||
|         return SUPER_USER; |         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 |     // 1. OAuth2Authentication strategy | ||||||
|     @Lazy |     @Lazy | ||||||
|     @Component |     @Component | ||||||
|  |  | ||||||
|  | @ -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.EntityProcessingReport; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | ||||||
| 
 | 
 | ||||||
| @Service | @Service | ||||||
|  | @ -49,44 +50,56 @@ public class BulkActionService { | ||||||
|         action.alreadyProcessed = true; |         action.alreadyProcessed = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void doBulkAction(final BulkAction action) { |     public Result<BulkAction> doBulkAction(final BulkAction action) { | ||||||
|         checkProcessing(action); |         return Result.tryCatch(() -> { | ||||||
| 
 | 
 | ||||||
|         final BulkActionSupportDAO<?> supportForSource = this.supporter.get(action.sourceType); |             checkProcessing(action); | ||||||
|         if (supportForSource == null) { |  | ||||||
|             action.alreadyProcessed = true; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         collectDependencies(action); |             final BulkActionSupportDAO<?> supportForSource = this.supporter | ||||||
| 
 |                     .get(action.sourceType); | ||||||
|         if (!action.dependencies.isEmpty()) { |             if (supportForSource == null) { | ||||||
|             // process dependencies first... |                 action.alreadyProcessed = true; | ||||||
|             final List<BulkActionSupportDAO<?>> dependancySupporter = |                 throw new IllegalArgumentException("No bulk action support for: " + action); | ||||||
|                     getDependancySupporter(action); |  | ||||||
| 
 |  | ||||||
|             for (final BulkActionSupportDAO<?> support : dependancySupporter) { |  | ||||||
|                 action.result.addAll(support.processBulkAction(action)); |  | ||||||
|             } |             } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         action.result.addAll(supportForSource.processBulkAction(action)); |             collectDependencies(action); | ||||||
| 
 | 
 | ||||||
|         processUserActivityLog(action); |             if (!action.dependencies.isEmpty()) { | ||||||
|         action.alreadyProcessed = true; |                 // 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) { |         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( |             // TODO | ||||||
|                 Collections.emptyList(), |             return new EntityProcessingReport( | ||||||
|                 Collections.emptyList(), |                     action.sources, | ||||||
|                 Collections.emptyMap()); |                     Collections.emptyList(), | ||||||
|  |                     Collections.emptyList()); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void processUserActivityLog(final BulkAction action) { |     private void processUserActivityLog(final BulkAction action) { | ||||||
|  | @ -98,7 +111,7 @@ public class BulkActionService { | ||||||
|             this.userActivityLogDAO.log( |             this.userActivityLogDAO.log( | ||||||
|                     action.type.activityType, |                     action.type.activityType, | ||||||
|                     key.entityType, |                     key.entityType, | ||||||
|                     key.entityId, |                     key.modelId, | ||||||
|                     "bulk action dependency"); |                     "bulk action dependency"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -106,7 +119,7 @@ public class BulkActionService { | ||||||
|             this.userActivityLogDAO.log( |             this.userActivityLogDAO.log( | ||||||
|                     action.type.activityType, |                     action.type.activityType, | ||||||
|                     key.entityType, |                     key.entityType, | ||||||
|                     key.entityId, |                     key.modelId, | ||||||
|                     "bulk action source"); |                     "bulk action source"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -32,7 +32,21 @@ public interface EntityDAO<T extends Entity> { | ||||||
|      * @param id the data base identifier of the 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 |      * @return Result refer the Entity instance with the specified database identifier or refer to an error if | ||||||
|      *         happened */ |      *         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. |     /** 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 |      * @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 */ |      * @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) { |         if (keys == null) { | ||||||
|             return Collections.emptyList(); |             return Collections.emptyList(); | ||||||
|  | @ -114,7 +128,7 @@ public interface EntityDAO<T extends Entity> { | ||||||
|         return keys |         return keys | ||||||
|                 .stream() |                 .stream() | ||||||
|                 .filter(key -> key.entityType == entityType) |                 .filter(key -> key.entityType == entityType) | ||||||
|                 .map(key -> Long.valueOf(key.entityId)) |                 .map(key -> Long.valueOf(key.modelId)) | ||||||
|                 .collect(Collectors.toList()); |                 .collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; | ||||||
| 
 | 
 | ||||||
| import java.util.Collection; | 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.Exam; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; | import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
|  | @ -27,8 +29,10 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam>, BulkActionSupportDA | ||||||
|             String name, |             String name, | ||||||
|             Exam.ExamStatus status, |             Exam.ExamStatus status, | ||||||
|             Exam.ExamType type, |             Exam.ExamType type, | ||||||
|             Long startTime, |             DateTime from, | ||||||
|             String owner, |             String owner, | ||||||
|             Boolean active); |             Boolean active); | ||||||
| 
 | 
 | ||||||
|  |     Result<Exam> save(Exam exam); | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -84,6 +84,7 @@ public interface UserActivityLogDAO extends UserRelatedEntityDAO<UserActivityLog | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Result<Collection<UserActivityLog>> all( |     Result<Collection<UserActivityLog>> all( | ||||||
|  |             Long InstitutionId, | ||||||
|             String userId, |             String userId, | ||||||
|             Long from, |             Long from, | ||||||
|             Long to, |             Long to, | ||||||
|  |  | ||||||
|  | @ -26,17 +26,11 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSuppor | ||||||
|  * within SEBServerUser. */ |  * within SEBServerUser. */ | ||||||
| public interface UserDAO extends ActivatableEntityDAO<UserInfo>, BulkActionSupportDAO<UserInfo> { | 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. |     /** Use this to get the user id (PK) from a given UUID. | ||||||
|      * |      * | ||||||
|      * @param uuid The UUID of the user |      * @param uuid The UUID of the user | ||||||
|      * @return the user id (PK) from a given UUID. */ |      * @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 |     /** Use this to get UserInfo by users username | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| import org.apache.commons.lang3.BooleanUtils; | import org.apache.commons.lang3.BooleanUtils; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.joda.time.DateTime; | ||||||
| import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter; | import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter; | ||||||
| import org.mybatis.dynamic.sql.select.QueryExpressionDSL; | import org.mybatis.dynamic.sql.select.QueryExpressionDSL; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
|  | @ -67,7 +68,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Exam> byId(final Long id) { |     public Result<Exam> byPK(final Long id) { | ||||||
|         return recordById(id) |         return recordById(id) | ||||||
|                 .flatMap(this::toDomainModel); |                 .flatMap(this::toDomainModel); | ||||||
|     } |     } | ||||||
|  | @ -108,7 +109,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|             final String name, |             final String name, | ||||||
|             final ExamStatus status, |             final ExamStatus status, | ||||||
|             final ExamType type, |             final ExamType type, | ||||||
|             final Long startTime, |             final DateTime from, | ||||||
|             final String owner, |             final String owner, | ||||||
|             final Boolean active) { |             final Boolean active) { | ||||||
| 
 | 
 | ||||||
|  | @ -121,8 +122,8 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (startTime != null) { |                 if (from != null) { | ||||||
|                     if (exam.startTime.getMillis() < startTime.longValue()) { |                     if (exam.startTime.isAfter(from)) { | ||||||
|                         return false; |                         return false; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -167,10 +168,40 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|         return Result.ofTODO(); |         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 |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) { |     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, |         final ExamRecord examRecord = new ExamRecord(null, null, null, null, null, | ||||||
|                 null, null, null, BooleanUtils.toInteger(active)); |                 null, null, null, BooleanUtils.toInteger(active)); | ||||||
| 
 | 
 | ||||||
|  | @ -196,7 +227,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { |     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { | ||||||
|         final List<Long> ids = extractIdsFromKeys(all); |         final List<Long> ids = extractPKsFromKeys(all); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| 
 | 
 | ||||||
|  | @ -235,7 +266,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<Exam>> bulkLoadEntities(final Collection<EntityKey> keys) { |     public Result<Collection<Exam>> bulkLoadEntities(final Collection<EntityKey> keys) { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             final List<Long> ids = extractIdsFromKeys(keys); |             final List<Long> ids = extractPKsFromKeys(keys); | ||||||
|             return this.examRecordMapper.selectByExample() |             return this.examRecordMapper.selectByExample() | ||||||
|                     .where(ExamRecordDynamicSqlSupport.id, isIn(ids)) |                     .where(ExamRecordDynamicSqlSupport.id, isIn(ids)) | ||||||
|                     .build() |                     .build() | ||||||
|  | @ -247,7 +278,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             return this.examRecordMapper.selectIdsByExample() |             return this.examRecordMapper.selectIdsByExample() | ||||||
|                     .where(ExamRecordDynamicSqlSupport.institutionId, |                     .where(ExamRecordDynamicSqlSupport.institutionId, | ||||||
|                             isEqualTo(Long.valueOf(institutionKey.entityId))) |                             isEqualTo(Long.valueOf(institutionKey.modelId))) | ||||||
|                     .build() |                     .build() | ||||||
|                     .execute() |                     .execute() | ||||||
|                     .stream() |                     .stream() | ||||||
|  | @ -260,7 +291,7 @@ public class ExamDAOImpl implements ExamDAO { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             return this.examRecordMapper.selectIdsByExample() |             return this.examRecordMapper.selectIdsByExample() | ||||||
|                     .where(ExamRecordDynamicSqlSupport.lmsSetupId, |                     .where(ExamRecordDynamicSqlSupport.lmsSetupId, | ||||||
|                             isEqualTo(Long.valueOf(lmsSetupKey.entityId))) |                             isEqualTo(Long.valueOf(lmsSetupKey.modelId))) | ||||||
|                     .build() |                     .build() | ||||||
|                     .execute() |                     .execute() | ||||||
|                     .stream() |                     .stream() | ||||||
|  |  | ||||||
|  | @ -56,7 +56,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Institution> byId(final Long id) { |     public Result<Institution> byPK(final Long id) { | ||||||
|         return recordById(id) |         return recordById(id) | ||||||
|                 .flatMap(InstitutionDAOImpl::toDomainModel); |                 .flatMap(InstitutionDAOImpl::toDomainModel); | ||||||
|     } |     } | ||||||
|  | @ -123,7 +123,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) { |     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( |         final InstitutionRecord institutionRecord = new InstitutionRecord( | ||||||
|                 null, null, null, BooleanUtils.toInteger(active), null); |                 null, null, null, BooleanUtils.toInteger(active), null); | ||||||
| 
 | 
 | ||||||
|  | @ -147,7 +147,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { |     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { | ||||||
|         final List<Long> ids = extractIdsFromKeys(all); |         final List<Long> ids = extractPKsFromKeys(all); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             this.institutionRecordMapper.deleteByExample() |             this.institutionRecordMapper.deleteByExample() | ||||||
|  | @ -177,7 +177,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<Institution>> bulkLoadEntities(final Collection<EntityKey> keys) { |     public Result<Collection<Institution>> bulkLoadEntities(final Collection<EntityKey> keys) { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             final List<Long> ids = extractIdsFromKeys(keys); |             final List<Long> ids = extractPKsFromKeys(keys); | ||||||
| 
 | 
 | ||||||
|             return this.institutionRecordMapper.selectByExample() |             return this.institutionRecordMapper.selectByExample() | ||||||
|                     .where(InstitutionRecordDynamicSqlSupport.id, isIn(ids)) |                     .where(InstitutionRecordDynamicSqlSupport.id, isIn(ids)) | ||||||
|  | @ -217,19 +217,18 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Result<InstitutionRecord> update(final Institution institution) { |     private Result<InstitutionRecord> update(final Institution institution) { | ||||||
|         return recordById(institution.id) |         return Result.tryCatch(() -> { | ||||||
|                 .map(record -> { |  | ||||||
| 
 | 
 | ||||||
|                     final InstitutionRecord newRecord = new InstitutionRecord( |             final InstitutionRecord newRecord = new InstitutionRecord( | ||||||
|                             institution.id, |                     institution.id, | ||||||
|                             institution.name, |                     institution.name, | ||||||
|                             institution.urlSuffix, |                     institution.urlSuffix, | ||||||
|                             null, |                     null, | ||||||
|                             institution.logoImage); |                     institution.logoImage); | ||||||
| 
 | 
 | ||||||
|                     this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord); |             this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord); | ||||||
|                     return this.institutionRecordMapper.selectByPrimaryKey(institution.id); |             return this.institutionRecordMapper.selectByPrimaryKey(institution.id); | ||||||
|                 }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static Result<Institution> toDomainModel(final InstitutionRecord record) { |     private static Result<Institution> toDomainModel(final InstitutionRecord record) { | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<LmsSetup> byId(final Long id) { |     public Result<LmsSetup> byPK(final Long id) { | ||||||
|         return recordById(id) |         return recordById(id) | ||||||
|                 .flatMap(LmsSetupDAOImpl::toDomainModel); |                 .flatMap(LmsSetupDAOImpl::toDomainModel); | ||||||
|     } |     } | ||||||
|  | @ -137,7 +137,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) { |     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( |         final LmsSetupRecord lmsSetupRecord = new LmsSetupRecord( | ||||||
|                 null, null, null, null, null, null, null, null, null, null, |                 null, null, null, null, null, null, null, null, null, null, | ||||||
|                 BooleanUtils.toIntegerObject(active)); |                 BooleanUtils.toIntegerObject(active)); | ||||||
|  | @ -162,7 +162,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { |     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { | ||||||
|         final List<Long> ids = extractIdsFromKeys(all); |         final List<Long> ids = extractPKsFromKeys(all); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             this.lmsSetupRecordMapper.deleteByExample() |             this.lmsSetupRecordMapper.deleteByExample() | ||||||
|  | @ -196,7 +196,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<LmsSetup>> bulkLoadEntities(final Collection<EntityKey> keys) { |     public Result<Collection<LmsSetup>> bulkLoadEntities(final Collection<EntityKey> keys) { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             final List<Long> ids = extractIdsFromKeys(keys); |             final List<Long> ids = extractPKsFromKeys(keys); | ||||||
| 
 | 
 | ||||||
|             return this.lmsSetupRecordMapper.selectByExample() |             return this.lmsSetupRecordMapper.selectByExample() | ||||||
|                     .where(LmsSetupRecordDynamicSqlSupport.id, isIn(ids)) |                     .where(LmsSetupRecordDynamicSqlSupport.id, isIn(ids)) | ||||||
|  | @ -213,7 +213,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             return this.lmsSetupRecordMapper.selectIdsByExample() |             return this.lmsSetupRecordMapper.selectIdsByExample() | ||||||
|                     .where(LmsSetupRecordDynamicSqlSupport.institutionId, |                     .where(LmsSetupRecordDynamicSqlSupport.institutionId, | ||||||
|                             isEqualTo(Long.valueOf(institutionKey.entityId))) |                             isEqualTo(Long.valueOf(institutionKey.modelId))) | ||||||
|                     .build() |                     .build() | ||||||
|                     .execute() |                     .execute() | ||||||
|                     .stream() |                     .stream() | ||||||
|  | @ -271,25 +271,24 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Result<LmsSetupRecord> update(final LmsSetup lmsSetup) { |     private Result<LmsSetupRecord> update(final LmsSetup lmsSetup) { | ||||||
|         return recordById(lmsSetup.id) |         return Result.tryCatch(() -> { | ||||||
|                 .map(record -> { |  | ||||||
| 
 | 
 | ||||||
|                     final LmsSetupRecord newRecord = new LmsSetupRecord( |             final LmsSetupRecord newRecord = new LmsSetupRecord( | ||||||
|                             lmsSetup.id, |                     lmsSetup.id, | ||||||
|                             lmsSetup.institutionId, |                     lmsSetup.institutionId, | ||||||
|                             lmsSetup.name, |                     lmsSetup.name, | ||||||
|                             (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, |                     (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, | ||||||
|                             lmsSetup.lmsApiUrl, |                     lmsSetup.lmsApiUrl, | ||||||
|                             lmsSetup.lmsAuthName, |                     lmsSetup.lmsAuthName, | ||||||
|                             lmsSetup.lmsAuthSecret, |                     lmsSetup.lmsAuthSecret, | ||||||
|                             lmsSetup.lmsRestApiToken, |                     lmsSetup.lmsRestApiToken, | ||||||
|                             lmsSetup.sebAuthName, |                     lmsSetup.sebAuthName, | ||||||
|                             lmsSetup.sebAuthSecret, |                     lmsSetup.sebAuthSecret, | ||||||
|                             null); |                     null); | ||||||
| 
 | 
 | ||||||
|                     this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord); |             this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord); | ||||||
|                     return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id); |             return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id); | ||||||
|                 }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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.mapper.UserRecordDynamicSqlSupport; | ||||||
| import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserActivityLogRecord; | 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.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.SEBServerUser; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler; | ||||||
|  | @ -49,18 +47,15 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { | ||||||
| 
 | 
 | ||||||
|     private final UserActivityLogRecordMapper userLogRecordMapper; |     private final UserActivityLogRecordMapper userLogRecordMapper; | ||||||
|     private final UserService userService; |     private final UserService userService; | ||||||
|     private final AuthorizationGrantService authorizationGrantService; |  | ||||||
|     private final PaginationService paginationService; |     private final PaginationService paginationService; | ||||||
| 
 | 
 | ||||||
|     public UserActivityLogDAOImpl( |     public UserActivityLogDAOImpl( | ||||||
|             final UserActivityLogRecordMapper userLogRecordMapper, |             final UserActivityLogRecordMapper userLogRecordMapper, | ||||||
|             final UserService userService, |             final UserService userService, | ||||||
|             final AuthorizationGrantService authorizationGrantService, |  | ||||||
|             final PaginationService paginationService) { |             final PaginationService paginationService) { | ||||||
| 
 | 
 | ||||||
|         this.userLogRecordMapper = userLogRecordMapper; |         this.userLogRecordMapper = userLogRecordMapper; | ||||||
|         this.userService = userService; |         this.userService = userService; | ||||||
|         this.authorizationGrantService = authorizationGrantService; |  | ||||||
|         this.paginationService = paginationService; |         this.paginationService = paginationService; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -172,7 +167,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<UserActivityLog> byId(final Long id) { |     public Result<UserActivityLog> byPK(final Long id) { | ||||||
|         return Result.tryCatch(() -> this.userLogRecordMapper.selectByPrimaryKey(id)) |         return Result.tryCatch(() -> this.userLogRecordMapper.selectByPrimaryKey(id)) | ||||||
|                 .flatMap(UserActivityLogDAOImpl::toDomainModel); |                 .flatMap(UserActivityLogDAOImpl::toDomainModel); | ||||||
|     } |     } | ||||||
|  | @ -180,7 +175,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { |     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { | ||||||
|         final List<Long> ids = extractIdsFromKeys(all); |         final List<Long> ids = extractPKsFromKeys(all); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             this.userLogRecordMapper.deleteByExample() |             this.userLogRecordMapper.deleteByExample() | ||||||
|  | @ -202,12 +197,24 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<UserActivityLog>> getAllForUser(final String userUuid) { |     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 |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<UserActivityLog>> all( |     public Result<Collection<UserActivityLog>> all( | ||||||
|  |             final Long institutionId, | ||||||
|             final String userId, |             final String userId, | ||||||
|             final Long from, |             final Long from, | ||||||
|             final Long to, |             final Long to, | ||||||
|  | @ -218,57 +225,30 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { | ||||||
|                     ? predicate |                     ? predicate | ||||||
|                     : model -> true; |                     : model -> true; | ||||||
| 
 | 
 | ||||||
|             final boolean basePrivilege = this.authorizationGrantService.hasBasePrivilege( |             return this.userLogRecordMapper.selectByExample() | ||||||
|                     EntityType.USER_ACTIVITY_LOG, |                     .join(UserRecordDynamicSqlSupport.userRecord) | ||||||
|                     PrivilegeType.READ_ONLY); |                     .on( | ||||||
| 
 |                             UserRecordDynamicSqlSupport.uuid, | ||||||
|             final Long institutionId = (basePrivilege) |                             SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid)) | ||||||
|                     ? null |                     .where( | ||||||
|                     : this.userService.getCurrentUser().institutionId(); |                             UserRecordDynamicSqlSupport.institutionId, | ||||||
| 
 |                             SqlBuilder.isEqualTo(institutionId)) | ||||||
|             return (institutionId == null) |                     .and( | ||||||
|                     ? this.userLogRecordMapper.selectByExample() |                             UserActivityLogRecordDynamicSqlSupport.userUuid, | ||||||
|                             .where( |                             SqlBuilder.isEqualToWhenPresent(userId)) | ||||||
|                                     UserActivityLogRecordDynamicSqlSupport.userUuid, |                     .and( | ||||||
|                                     SqlBuilder.isEqualToWhenPresent(userId)) |                             UserActivityLogRecordDynamicSqlSupport.timestamp, | ||||||
|                             .and( |                             SqlBuilder.isGreaterThanOrEqualToWhenPresent(from)) | ||||||
|                                     UserActivityLogRecordDynamicSqlSupport.timestamp, |                     .and( | ||||||
|                                     SqlBuilder.isGreaterThanOrEqualToWhenPresent(from)) |                             UserActivityLogRecordDynamicSqlSupport.timestamp, | ||||||
|                             .and( |                             SqlBuilder.isLessThanWhenPresent(to)) | ||||||
|                                     UserActivityLogRecordDynamicSqlSupport.timestamp, |                     .build() | ||||||
|                                     SqlBuilder.isLessThanWhenPresent(to)) |                     .execute() | ||||||
|                             .build() |                     .stream() | ||||||
|                             .execute() |                     .filter(_predicate) | ||||||
|                             .stream() |                     .map(UserActivityLogDAOImpl::toDomainModel) | ||||||
|                             .filter(_predicate) |                     .flatMap(Result::skipOnError) | ||||||
|                             .map(UserActivityLogDAOImpl::toDomainModel) |                     .collect(Collectors.toList()); | ||||||
|                             .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()); |  | ||||||
| 
 | 
 | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -83,22 +83,22 @@ public class UserDaoImpl implements UserDAO { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<UserInfo> byId(final Long id) { |     public Result<UserInfo> byPK(final Long id) { | ||||||
|         return Result.tryCatch(() -> this.userRecordMapper.selectByPrimaryKey(id)) |         return Result.tryCatch(() -> this.userRecordMapper.selectByPrimaryKey(id)) | ||||||
|                 .flatMap(this::toDomainModel); |                 .flatMap(this::toDomainModel); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<UserInfo> byUuid(final String uuid) { |     public Result<UserInfo> byModelId(final String modelId) { | ||||||
|         return recordByUUID(uuid) |         return recordByUUID(modelId) | ||||||
|                 .flatMap(this::toDomainModel); |                 .flatMap(this::toDomainModel); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Long> pkForUUID(final String uuid) { |     public Result<Long> pkForModelId(final String modelId) { | ||||||
|         return recordByUUID(uuid) |         return recordByUUID(modelId) | ||||||
|                 .map(r -> r.getId()); |                 .map(r -> r.getId()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -191,7 +191,7 @@ public class UserDaoImpl implements UserDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) { |     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( |         final UserRecord userRecord = new UserRecord( | ||||||
|                 null, null, null, null, null, null, null, null, null, |                 null, null, null, null, null, null, null, null, null, | ||||||
|                 BooleanUtils.toIntegerObject(active)); |                 BooleanUtils.toIntegerObject(active)); | ||||||
|  | @ -216,7 +216,7 @@ public class UserDaoImpl implements UserDAO { | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { |     public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) { | ||||||
|         final List<Long> ids = extractIdsFromKeys(all); |         final List<Long> ids = extractPKsFromKeys(all); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             this.userRecordMapper.deleteByExample() |             this.userRecordMapper.deleteByExample() | ||||||
|  | @ -259,7 +259,7 @@ public class UserDaoImpl implements UserDAO { | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     public Result<Collection<UserInfo>> bulkLoadEntities(final Collection<EntityKey> keys) { |     public Result<Collection<UserInfo>> bulkLoadEntities(final Collection<EntityKey> keys) { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             final List<Long> ids = extractIdsFromKeys(keys); |             final List<Long> ids = extractPKsFromKeys(keys); | ||||||
| 
 | 
 | ||||||
|             return this.userRecordMapper.selectByExample() |             return this.userRecordMapper.selectByExample() | ||||||
|                     .where(InstitutionRecordDynamicSqlSupport.id, isIn(ids)) |                     .where(InstitutionRecordDynamicSqlSupport.id, isIn(ids)) | ||||||
|  | @ -273,12 +273,12 @@ public class UserDaoImpl implements UserDAO { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @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) { |         if (keys == null || keys.isEmpty() || keys.iterator().next().isIdPK) { | ||||||
|             return UserDAO.super.extractIdsFromKeys(keys); |             return UserDAO.super.extractPKsFromKeys(keys); | ||||||
|         } else { |         } else { | ||||||
|             final List<String> uuids = keys.stream() |             final List<String> uuids = keys.stream() | ||||||
|                     .map(key -> key.entityId) |                     .map(key -> key.modelId) | ||||||
|                     .collect(Collectors.toList()); |                     .collect(Collectors.toList()); | ||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
|  | @ -299,7 +299,7 @@ public class UserDaoImpl implements UserDAO { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             return this.userRecordMapper.selectIdsByExample() |             return this.userRecordMapper.selectIdsByExample() | ||||||
|                     .where(UserRecordDynamicSqlSupport.institutionId, |                     .where(UserRecordDynamicSqlSupport.institutionId, | ||||||
|                             isEqualTo(Long.valueOf(institutionKey.entityId))) |                             isEqualTo(Long.valueOf(institutionKey.modelId))) | ||||||
|                     .build() |                     .build() | ||||||
|                     .execute() |                     .execute() | ||||||
|                     .stream() |                     .stream() | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.lms; | 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.model.institution.LmsSetup; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| 
 | 
 | ||||||
|  | @ -17,8 +19,8 @@ public interface LmsAPIService { | ||||||
| 
 | 
 | ||||||
|     Result<LmsAPITemplate> createLmsAPITemplate(LmsSetup lmsSetup); |     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); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl; | package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl; | ||||||
| 
 | 
 | ||||||
|  | import java.io.InputStream; | ||||||
|  | 
 | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | ||||||
|  | @ -30,7 +32,7 @@ public class LmsAPIServiceImpl implements LmsAPIService { | ||||||
|     @Override |     @Override | ||||||
|     public Result<LmsAPITemplate> createLmsAPITemplate(final Long lmsSetupId) { |     public Result<LmsAPITemplate> createLmsAPITemplate(final Long lmsSetupId) { | ||||||
|         return this.lmsSetupDAO |         return this.lmsSetupDAO | ||||||
|                 .byId(lmsSetupId) |                 .byPK(lmsSetupId) | ||||||
|                 .flatMap(this::createLmsAPITemplate); |                 .flatMap(this::createLmsAPITemplate); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -46,14 +48,14 @@ public class LmsAPIServiceImpl implements LmsAPIService { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public Result<byte[]> createSEBStartConfiguration(final Long lmsSetupId) { |     public Result<InputStream> createSEBStartConfiguration(final Long lmsSetupId) { | ||||||
|         return this.lmsSetupDAO |         return this.lmsSetupDAO | ||||||
|                 .byId(lmsSetupId) |                 .byPK(lmsSetupId) | ||||||
|                 .flatMap(this::createSEBStartConfiguration); |                 .flatMap(this::createSEBStartConfiguration); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @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 |         // 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 |         // A SEB start configuration should at least contain the SEB-Client-Credentials to access the SEB Server API | ||||||
|  |  | ||||||
|  | @ -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)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -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(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -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); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -21,8 +21,8 @@ import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; |  | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | 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.EntityProcessingReport; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | ||||||
|  | @ -62,24 +62,18 @@ public class InstitutionController { | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/self", method = RequestMethod.GET) |     @RequestMapping(path = "/self", method = RequestMethod.GET) | ||||||
|     public Institution getOwn() { |     public Institution getOwn() { | ||||||
| 
 |  | ||||||
|         checkBaseReadPrivilege(); |  | ||||||
| 
 |  | ||||||
|         final SEBServerUser currentUser = this.authorizationGrantService |         final SEBServerUser currentUser = this.authorizationGrantService | ||||||
|                 .getUserService() |                 .getUserService() | ||||||
|                 .getCurrentUser(); |                 .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) |     @RequestMapping(path = "/{id}", method = RequestMethod.GET) | ||||||
|     public Institution getById(@PathVariable final Long id) { |     public Institution getById(@PathVariable final Long id) { | ||||||
| 
 |  | ||||||
|         checkBaseReadPrivilege(); |  | ||||||
| 
 |  | ||||||
|         return this.institutionDAO |         return this.institutionDAO | ||||||
|                 .byId(id) |                 .byPK(id) | ||||||
|                 .flatMap(inst -> this.authorizationGrantService.checkGrantOnEntity( |                 .flatMap(inst -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|                         inst, |                         inst, | ||||||
|                         PrivilegeType.READ_ONLY)) |                         PrivilegeType.READ_ONLY)) | ||||||
|  | @ -90,8 +84,6 @@ public class InstitutionController { | ||||||
|     public Collection<Institution> getAll( |     public Collection<Institution> getAll( | ||||||
|             @RequestParam(name = Institution.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { |             @RequestParam(name = Institution.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { | ||||||
| 
 | 
 | ||||||
|         checkBaseReadPrivilege(); |  | ||||||
| 
 |  | ||||||
|         if (!this.authorizationGrantService.hasBasePrivilege( |         if (!this.authorizationGrantService.hasBasePrivilege( | ||||||
|                 EntityType.INSTITUTION, |                 EntityType.INSTITUTION, | ||||||
|                 PrivilegeType.READ_ONLY)) { |                 PrivilegeType.READ_ONLY)) { | ||||||
|  | @ -126,13 +118,15 @@ public class InstitutionController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}/activate", method = RequestMethod.POST) |     @RequestMapping(path = "/{id}/activate", method = RequestMethod.POST) | ||||||
|     public Institution activate(@PathVariable final Long id) { |     public EntityProcessingReport activate(@PathVariable final Long id) { | ||||||
|         return setActive(id, true); |         return setActive(id, true) | ||||||
|  |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST) |     @RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST) | ||||||
|     public Institution deactivate(@PathVariable final Long id) { |     public EntityProcessingReport deactivate(@PathVariable final Long id) { | ||||||
|         return setActive(id, false); |         return setActive(id, false) | ||||||
|  |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}/delete", method = RequestMethod.DELETE) |     @RequestMapping(path = "/{id}/delete", method = RequestMethod.DELETE) | ||||||
|  | @ -142,7 +136,8 @@ public class InstitutionController { | ||||||
|         return this.bulkActionService.createReport(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 Type.DEACTIVATE, |                 Type.DEACTIVATE, | ||||||
|                 EntityType.INSTITUTION, |                 EntityType.INSTITUTION, | ||||||
|                 new EntityKey(id, EntityType.INSTITUTION))); |                 new EntityKey(id, EntityType.INSTITUTION))) | ||||||
|  |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE) |     @RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE) | ||||||
|  | @ -152,7 +147,8 @@ public class InstitutionController { | ||||||
|         return this.bulkActionService.createReport(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 Type.HARD_DELETE, |                 Type.HARD_DELETE, | ||||||
|                 EntityType.INSTITUTION, |                 EntityType.INSTITUTION, | ||||||
|                 new EntityKey(id, EntityType.INSTITUTION))); |                 new EntityKey(id, EntityType.INSTITUTION))) | ||||||
|  |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void checkPrivilegeForInstitution(final Long id, final PrivilegeType type) { |     private void checkPrivilegeForInstitution(final Long id, final PrivilegeType type) { | ||||||
|  | @ -160,24 +156,21 @@ public class InstitutionController { | ||||||
|                 EntityType.INSTITUTION, |                 EntityType.INSTITUTION, | ||||||
|                 type); |                 type); | ||||||
| 
 | 
 | ||||||
|         this.institutionDAO.byId(id) |         this.institutionDAO.byPK(id) | ||||||
|                 .flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity( |                 .flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|                         institution, |                         institution, | ||||||
|                         type)) |                         type)) | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Institution setActive(final Long id, final boolean active) { |     private Result<EntityProcessingReport> setActive(final Long id, final boolean active) { | ||||||
|         checkPrivilegeForInstitution(id, PrivilegeType.MODIFY); |         checkPrivilegeForInstitution(id, PrivilegeType.MODIFY); | ||||||
| 
 | 
 | ||||||
|         this.bulkActionService.doBulkAction(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 (active) ? Type.ACTIVATE : Type.DEACTIVATE, |                 (active) ? Type.ACTIVATE : Type.DEACTIVATE, | ||||||
|                 EntityType.INSTITUTION, |                 EntityType.INSTITUTION, | ||||||
|                 new EntityKey(id, EntityType.INSTITUTION))); |                 new EntityKey(id, EntityType.INSTITUTION))); | ||||||
| 
 | 
 | ||||||
|         return this.institutionDAO |  | ||||||
|                 .byId(id) |  | ||||||
|                 .getOrThrow(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Result<Institution> save(final Institution institution, final PrivilegeType privilegeType) { |     private Result<Institution> save(final Institution institution, final PrivilegeType privilegeType) { | ||||||
|  | @ -192,10 +185,4 @@ public class InstitutionController { | ||||||
|                 .flatMap(inst -> this.userActivityLogDAO.log(activityType, inst)); |                 .flatMap(inst -> this.userActivityLogDAO.log(activityType, inst)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void checkBaseReadPrivilege() { |  | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |  | ||||||
|                 EntityType.INSTITUTION, |  | ||||||
|                 PrivilegeType.READ_ONLY); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,12 +8,18 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.weblayer.api; | package ch.ethz.seb.sebserver.webservice.weblayer.api; | ||||||
| 
 | 
 | ||||||
|  | import java.io.InputStream; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
|  | import javax.servlet.http.HttpServletResponse; | ||||||
| import javax.validation.Valid; | 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.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.PathVariable; | ||||||
| import org.springframework.web.bind.annotation.RequestBody; | import org.springframework.web.bind.annotation.RequestBody; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | @ -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.profile.WebServiceProfile; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService; | 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.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; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type; | 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.bulkaction.BulkActionService; | ||||||
|  | @ -66,44 +71,42 @@ public class LmsSetupController { | ||||||
|         this.lmsAPIService = lmsAPIService; |         this.lmsAPIService = lmsAPIService; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @InitBinder | ||||||
|  |     public void initBinder(final WebDataBinder binder) throws Exception { | ||||||
|  |         this.authorizationGrantService | ||||||
|  |                 .getUserService() | ||||||
|  |                 .addUsersInstitutionDefaultPropertySupport(binder); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @RequestMapping(method = RequestMethod.GET) |     @RequestMapping(method = RequestMethod.GET) | ||||||
|     public Collection<LmsSetup> getAll( |     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_NAME, required = false) final String name, | ||||||
|             @RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType, |             @RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType, | ||||||
|             @RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { |             @RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { | ||||||
| 
 | 
 | ||||||
|         checkBaseReadPrivilege(); |         checkReadPrivilege(institutionId); | ||||||
| 
 |  | ||||||
|         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); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         return this.lmsSetupDAO |         return this.lmsSetupDAO | ||||||
|                 .allMatching(instId, name, lmsType, active) |                 .allMatching(institutionId, name, lmsType, active) | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/names", method = RequestMethod.GET) |     @RequestMapping(path = "/names", method = RequestMethod.GET) | ||||||
|     public Collection<EntityKeyAndName> getNames( |     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_NAME, required = false) final String name, | ||||||
|             @RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType, |             @RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType, | ||||||
|             @RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { |             @RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) { | ||||||
| 
 | 
 | ||||||
|  |         checkReadPrivilege(institutionId); | ||||||
|  | 
 | ||||||
|         return getAll(institutionId, name, lmsType, active) |         return getAll(institutionId, name, lmsType, active) | ||||||
|                 .stream() |                 .stream() | ||||||
|                 .map(LmsSetup::toName) |                 .map(LmsSetup::toName) | ||||||
|  | @ -112,13 +115,10 @@ public class LmsSetupController { | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}", method = RequestMethod.GET) |     @RequestMapping(path = "/{id}", method = RequestMethod.GET) | ||||||
|     public LmsSetup getById(@PathVariable final Long id) { |     public LmsSetup getById(@PathVariable final Long id) { | ||||||
| 
 |  | ||||||
|         checkBaseReadPrivilege(); |  | ||||||
| 
 |  | ||||||
|         return this.lmsSetupDAO |         return this.lmsSetupDAO | ||||||
|                 .byId(id) |                 .byPK(id) | ||||||
|                 .flatMap(inst -> this.authorizationGrantService.checkGrantOnEntity( |                 .flatMap(lmsSetup -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|                         inst, |                         lmsSetup, | ||||||
|                         PrivilegeType.READ_ONLY)) |                         PrivilegeType.READ_ONLY)) | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
|  | @ -127,15 +127,28 @@ public class LmsSetupController { | ||||||
|             path = "/create_seb_config/{id}", |             path = "/create_seb_config/{id}", | ||||||
|             method = RequestMethod.GET, |             method = RequestMethod.GET, | ||||||
|             produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) // TODO check if this is the right format |             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( |         this.authorizationGrantService.checkHasAnyPrivilege( | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 PrivilegeType.WRITE); |                 PrivilegeType.WRITE); | ||||||
| 
 | 
 | ||||||
|         return this.lmsAPIService |         response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | ||||||
|                 .createSEBStartConfiguration(id) |         response.setStatus(HttpStatus.OK.value()); | ||||||
|                 .getOrThrow(); | 
 | ||||||
|  |         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) |     @RequestMapping(path = "/create", method = RequestMethod.PUT) | ||||||
|  | @ -151,12 +164,12 @@ public class LmsSetupController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}/activate", method = RequestMethod.POST) |     @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); |         return setActive(id, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST) |     @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); |         return setActive(id, false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -167,7 +180,8 @@ public class LmsSetupController { | ||||||
|         return this.bulkActionService.createReport(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 Type.DEACTIVATE, |                 Type.DEACTIVATE, | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 new EntityKey(id, EntityType.LMS_SETUP))); |                 new EntityKey(id, EntityType.LMS_SETUP))) | ||||||
|  |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE) |     @RequestMapping(path = "/{id}/hard-delete", method = RequestMethod.DELETE) | ||||||
|  | @ -177,31 +191,29 @@ public class LmsSetupController { | ||||||
|         return this.bulkActionService.createReport(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 Type.HARD_DELETE, |                 Type.HARD_DELETE, | ||||||
|                 EntityType.LMS_SETUP, |                 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( |         this.authorizationGrantService.checkHasAnyPrivilege( | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 type); |                 type); | ||||||
| 
 | 
 | ||||||
|         this.lmsSetupDAO.byId(id) |         this.lmsSetupDAO.byPK(lmsSetupId) | ||||||
|                 .flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity( |                 .flatMap(institution -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|                         institution, |                         institution, | ||||||
|                         type)) |                         type)) | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private LmsSetup setActive(final Long id, final boolean active) { |     private EntityProcessingReport setActive(final Long id, final boolean active) { | ||||||
|         checkPrivilegeForInstitution(id, PrivilegeType.MODIFY); |         checkPrivilegeForInstitution(id, PrivilegeType.MODIFY); | ||||||
| 
 | 
 | ||||||
|         this.bulkActionService.doBulkAction(new BulkAction( |         return this.bulkActionService.createReport(new BulkAction( | ||||||
|                 (active) ? Type.ACTIVATE : Type.DEACTIVATE, |                 (active) ? Type.ACTIVATE : Type.DEACTIVATE, | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 new EntityKey(id, EntityType.LMS_SETUP))); |                 new EntityKey(id, EntityType.LMS_SETUP))) | ||||||
| 
 |  | ||||||
|         return this.lmsSetupDAO |  | ||||||
|                 .byId(id) |  | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -214,13 +226,14 @@ public class LmsSetupController { | ||||||
|         return this.authorizationGrantService |         return this.authorizationGrantService | ||||||
|                 .checkGrantOnEntity(lmsSetup, privilegeType) |                 .checkGrantOnEntity(lmsSetup, privilegeType) | ||||||
|                 .flatMap(this.lmsSetupDAO::save) |                 .flatMap(this.lmsSetupDAO::save) | ||||||
|                 .flatMap(inst -> this.userActivityLogDAO.log(activityType, inst)); |                 .flatMap(exam -> this.userActivityLogDAO.log(activityType, exam)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void checkBaseReadPrivilege() { |     private void checkReadPrivilege(final Long institutionId) { | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |         this.authorizationGrantService.checkPrivilege( | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 PrivilegeType.READ_ONLY); |                 PrivilegeType.READ_ONLY, | ||||||
|  |                 institutionId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -74,19 +74,20 @@ public class QuizImportController { | ||||||
|             @RequestParam(name = LMS_SETUP.ATTR_ID, required = true) final Long lmsSetupId, |             @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_NAME, required = false) final String nameLike, | ||||||
|             @RequestParam(name = QuizData.FILTER_ATTR_START_TIME, required = false) final String startTime, |             @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 = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber, | ||||||
|             @RequestParam(name = QuizData.PAGE_ATTR_SIZE, required = false) final Integer pageSize, |             @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize, | ||||||
|             @RequestParam(name = QuizData.PAGE_ATTR_SORT_BY, required = false) final String orderBy, |             @RequestParam(name = Page.ATTR_SORT_BY, required = false) final String orderBy, | ||||||
|             @RequestParam(name = QuizData.PAGE_ATTR_SORT_ORDER, required = false) final String sortOrder) { |             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final String sortOrder) { | ||||||
| 
 |  | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |  | ||||||
|                 EntityType.EXAM, |  | ||||||
|                 PrivilegeType.READ_ONLY); |  | ||||||
| 
 | 
 | ||||||
|         final LmsAPITemplate lmsAPITemplate = this.lmsAPIService |         final LmsAPITemplate lmsAPITemplate = this.lmsAPIService | ||||||
|                 .createLmsAPITemplate(lmsSetupId) |                 .createLmsAPITemplate(lmsSetupId) | ||||||
|                 .getOrThrow(); |                 .getOrThrow(); | ||||||
| 
 | 
 | ||||||
|  |         this.authorizationGrantService.checkPrivilege( | ||||||
|  |                 EntityType.EXAM, | ||||||
|  |                 PrivilegeType.READ_ONLY, | ||||||
|  |                 lmsAPITemplate.lmsSetup().institutionId); | ||||||
|  | 
 | ||||||
|         return lmsAPITemplate.getQuizzesPage( |         return lmsAPITemplate.getQuizzesPage( | ||||||
|                 nameLike, |                 nameLike, | ||||||
|                 Utils.dateTimeStringToTimestamp(startTime, null), |                 Utils.dateTimeStringToTimestamp(startTime, null), | ||||||
|  |  | ||||||
|  | @ -18,6 +18,8 @@ public class RestAPI { | ||||||
| 
 | 
 | ||||||
|     public static final String ENDPOINT_QUIZ_IMPORT = "/quiz"; |     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"; |     public static final String ENDPOINT_USER_ACTIVITY_LOG = "/useractivity"; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,15 +13,14 @@ import java.util.Collection; | ||||||
| import javax.validation.Valid; | import javax.validation.Valid; | ||||||
| 
 | 
 | ||||||
| import org.springframework.context.ApplicationEventPublisher; | 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.RequestBody; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMethod; | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | 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.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserFilter; | 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.AuthorizationGrantService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | ||||||
| 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.bulkaction.BulkActionService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | 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.dao.UserActivityLogDAO.ActivityType; | ||||||
|  | @ -45,11 +42,10 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint; | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACCOUNT) | @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 UserDAO userDao; | ||||||
|     private final AuthorizationGrantService authorizationGrantService; |     private final AuthorizationGrantService authorizationGrantService; | ||||||
|     private final UserService userService; |  | ||||||
|     private final UserActivityLogDAO userActivityLogDAO; |     private final UserActivityLogDAO userActivityLogDAO; | ||||||
|     private final PaginationService paginationService; |     private final PaginationService paginationService; | ||||||
|     private final BulkActionService bulkActionService; |     private final BulkActionService bulkActionService; | ||||||
|  | @ -58,34 +54,40 @@ public class UserAccountController { | ||||||
|     public UserAccountController( |     public UserAccountController( | ||||||
|             final UserDAO userDao, |             final UserDAO userDao, | ||||||
|             final AuthorizationGrantService authorizationGrantService, |             final AuthorizationGrantService authorizationGrantService, | ||||||
|             final UserService userService, |  | ||||||
|             final UserActivityLogDAO userActivityLogDAO, |             final UserActivityLogDAO userActivityLogDAO, | ||||||
|             final PaginationService paginationService, |             final PaginationService paginationService, | ||||||
|             final BulkActionService bulkActionService, |             final BulkActionService bulkActionService, | ||||||
|             final ApplicationEventPublisher applicationEventPublisher) { |             final ApplicationEventPublisher applicationEventPublisher) { | ||||||
| 
 | 
 | ||||||
|  |         super(authorizationGrantService, bulkActionService, userDao); | ||||||
|         this.userDao = userDao; |         this.userDao = userDao; | ||||||
|         this.authorizationGrantService = authorizationGrantService; |         this.authorizationGrantService = authorizationGrantService; | ||||||
|         this.userService = userService; |  | ||||||
|         this.userActivityLogDAO = userActivityLogDAO; |         this.userActivityLogDAO = userActivityLogDAO; | ||||||
|         this.paginationService = paginationService; |         this.paginationService = paginationService; | ||||||
|         this.bulkActionService = bulkActionService; |         this.bulkActionService = bulkActionService; | ||||||
|         this.applicationEventPublisher = applicationEventPublisher; |         this.applicationEventPublisher = applicationEventPublisher; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @InitBinder | ||||||
|  |     public void initBinder(final WebDataBinder binder) throws Exception { | ||||||
|  |         this.authorizationGrantService | ||||||
|  |                 .getUserService() | ||||||
|  |                 .addUsersInstitutionDefaultPropertySupport(binder); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @RequestMapping(method = RequestMethod.GET) |     @RequestMapping(method = RequestMethod.GET) | ||||||
|     public Collection<UserInfo> getAll( |     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_ACTIVE, required = false) final Boolean active, | ||||||
|             @RequestParam(name = UserFilter.FILTER_ATTR_NAME, required = false) final String name, |             @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_USER_NAME, required = false) final String username, | ||||||
|             @RequestParam(name = UserFilter.FILTER_ATTR_EMAIL, required = false) final String email, |             @RequestParam(name = UserFilter.FILTER_ATTR_EMAIL, required = false) final String email, | ||||||
|             @RequestParam(name = UserFilter.FILTER_ATTR_LOCALE, required = false) final String locale) { |             @RequestParam(name = UserFilter.FILTER_ATTR_LOCALE, required = false) final String locale) { | ||||||
| 
 | 
 | ||||||
|         // fist check if current user has any privileges for this action |         checkReadPrivilege(institutionId); | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |  | ||||||
|                 EntityType.USER, |  | ||||||
|                 PrivilegeType.READ_ONLY); |  | ||||||
| 
 | 
 | ||||||
|         this.paginationService.setDefaultLimit(UserRecordDynamicSqlSupport.userRecord); |         this.paginationService.setDefaultLimit(UserRecordDynamicSqlSupport.userRecord); | ||||||
|         return getAll(createUserFilter(institutionId, active, name, username, email, locale)); |         return getAll(createUserFilter(institutionId, active, name, username, email, locale)); | ||||||
|  | @ -93,7 +95,10 @@ public class UserAccountController { | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/page", method = RequestMethod.GET) |     @RequestMapping(path = "/page", method = RequestMethod.GET) | ||||||
|     public Page<UserInfo> getPage( |     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_ACTIVE, required = false) final Boolean active, | ||||||
|             @RequestParam(name = UserFilter.FILTER_ATTR_NAME, required = false) final String name, |             @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_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_BY, required = false) final String sortBy, | ||||||
|             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { |             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { | ||||||
| 
 | 
 | ||||||
|         // fist check if current user has any privileges for this action |         checkReadPrivilege(institutionId); | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |  | ||||||
|                 EntityType.USER, |  | ||||||
|                 PrivilegeType.READ_ONLY); |  | ||||||
| 
 | 
 | ||||||
|         return this.paginationService.getPage( |         return this.paginationService.getPage( | ||||||
|                 pageNumber, |                 pageNumber, | ||||||
|  | @ -121,21 +123,22 @@ public class UserAccountController { | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/me", method = RequestMethod.GET) |     @RequestMapping(path = "/me", method = RequestMethod.GET) | ||||||
|     public UserInfo loggedInUser() { |     public UserInfo loggedInUser() { | ||||||
|         return this.userService |         return this.authorizationGrantService | ||||||
|  |                 .getUserService() | ||||||
|                 .getCurrentUser() |                 .getCurrentUser() | ||||||
|                 .getUserInfo(); |                 .getUserInfo(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{uuid}", method = RequestMethod.GET) | //    @Override | ||||||
|     public UserInfo accountInfo(@PathVariable final String uuid) { | //    @RequestMapping(path = "/{uuid}", method = RequestMethod.GET) | ||||||
|         return this.userDao | //    public UserInfo accountInfo(@PathVariable final String uuid) { | ||||||
|                 .byUuid(uuid) | //        return this.userDao | ||||||
|                 .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity( | //                .byModelId(uuid) | ||||||
|                         userInfo, | //                .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|                         PrivilegeType.READ_ONLY)) | //                        userInfo, | ||||||
|                 .getOrThrow(); | //                        PrivilegeType.READ_ONLY)) | ||||||
| 
 | //                .getOrThrow(); | ||||||
|     } | //    } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/create", method = RequestMethod.PUT) |     @RequestMapping(path = "/create", method = RequestMethod.PUT) | ||||||
|     public UserInfo createUser(@Valid @RequestBody final UserMod userData) { |     public UserInfo createUser(@Valid @RequestBody final UserMod userData) { | ||||||
|  | @ -150,60 +153,52 @@ public class UserAccountController { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{uuid}/activate", method = RequestMethod.POST) | //    @Override | ||||||
|     public UserInfo activateUser(@PathVariable final String uuid) { | //    @RequestMapping(path = "/{uuid}/activate", method = RequestMethod.POST) | ||||||
|         return setActive(uuid, true); | //    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) | //    private void checkPrivilegeForUser(final String uuid, final PrivilegeType type) { | ||||||
|     public UserInfo deactivateUser(@PathVariable final String uuid) { | //        this.authorizationGrantService.checkHasAnyPrivilege( | ||||||
|         return setActive(uuid, false); | //                EntityType.USER, | ||||||
|     } | //                type); | ||||||
|  | // | ||||||
|  | //        this.userDao.byModelId(uuid) | ||||||
|  | //                .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity( | ||||||
|  | //                        userInfo, | ||||||
|  | //                        type)) | ||||||
|  | //                .getOrThrow(); | ||||||
|  | //    } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/{uuid}/delete", method = RequestMethod.DELETE) | //    private Result<EntityProcessingReport> setActive(final String uuid, final boolean active) { | ||||||
|     public EntityProcessingReport deleteUser(@PathVariable final String uuid) { | //        this.checkPrivilegeForUser(uuid, PrivilegeType.MODIFY); | ||||||
|         checkPrivilegeForUser(uuid, PrivilegeType.WRITE); | // | ||||||
| 
 | //        return this.bulkActionService.createReport(new BulkAction( | ||||||
|         return this.bulkActionService.createReport(new BulkAction( | //                (active) ? Type.ACTIVATE : Type.DEACTIVATE, | ||||||
|                 Type.DEACTIVATE, | //                EntityType.USER, | ||||||
|                 EntityType.USER, | //                new EntityKey(uuid, EntityType.USER, false))); | ||||||
|                 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<UserInfo> _saveUser(final UserMod userData, final PrivilegeType privilegeType) { |     private Result<UserInfo> _saveUser(final UserMod userData, final PrivilegeType privilegeType) { | ||||||
| 
 | 
 | ||||||
|  | @ -261,4 +256,11 @@ public class UserAccountController { | ||||||
|                         : null; |                         : null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void checkReadPrivilege(final Long institutionId) { | ||||||
|  |         this.authorizationGrantService.checkPrivilege( | ||||||
|  |                 EntityType.USER, | ||||||
|  |                 PrivilegeType.READ_ONLY, | ||||||
|  |                 institutionId); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,8 +13,11 @@ import java.util.Collection; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  | import java.util.function.Predicate; | ||||||
| 
 | 
 | ||||||
| import org.apache.commons.lang3.StringUtils; | 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.PathVariable; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMethod; | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
|  | @ -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.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | 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.UserActivityLogRecordDynamicSqlSupport; | ||||||
| import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; | 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.PaginationService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
|  | @ -52,84 +58,113 @@ public class UserActivityLogController { | ||||||
|         this.paginationService = paginationService; |         this.paginationService = paginationService; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @InitBinder | ||||||
|  |     public void initBinder(final WebDataBinder binder) throws Exception { | ||||||
|  |         this.authorizationGrantService | ||||||
|  |                 .getUserService() | ||||||
|  |                 .addUsersInstitutionDefaultPropertySupport(binder); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @RequestMapping(method = RequestMethod.GET) |     @RequestMapping(method = RequestMethod.GET) | ||||||
|     public Collection<UserActivityLog> getAll( |     public Collection<UserActivityLog> getAll( | ||||||
|             @RequestParam(required = false) final Long from, |             @RequestParam( | ||||||
|             @RequestParam(required = false) final Long to, |                     name = UserActivityLog.FILTER_ATTR_INSTITUTION, | ||||||
|             @RequestParam(required = false) final String activityTypes, |                     required = true, | ||||||
|             @RequestParam(required = false) final String entityTypes) { |                     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); |         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) |     @RequestMapping(path = "/{userId}", method = RequestMethod.GET) | ||||||
|     public Collection<UserActivityLog> getAllForUser( |     public Collection<UserActivityLog> getAllForUser( | ||||||
|             @PathVariable final String userId, |             @PathVariable final String userId, | ||||||
|             @RequestParam(required = false) final Long from, |             @RequestParam( | ||||||
|             @RequestParam(required = false) final Long to, |                     name = UserActivityLog.FILTER_ATTR_INSTITUTION, | ||||||
|             @RequestParam(required = false) final String activityTypes, |                     required = true, | ||||||
|             @RequestParam(required = false) final String entityTypes) { |                     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); |         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) |     @RequestMapping(path = "/page", method = RequestMethod.GET) | ||||||
|     public Page<UserActivityLog> getPage( |     public Page<UserActivityLog> getPage( | ||||||
|             @RequestParam(required = false) final Long from, |             @RequestParam( | ||||||
|             @RequestParam(required = false) final Long to, |                     name = UserActivityLog.FILTER_ATTR_INSTITUTION, | ||||||
|             @RequestParam(required = false) final String activityTypes, |                     required = true, | ||||||
|             @RequestParam(required = false) final String entityTypes, |                     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_NUMBER, required = false) final Integer pageNumber, | ||||||
|             @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize, |             @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_BY, required = false) final String sortBy, | ||||||
|             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { |             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { | ||||||
| 
 | 
 | ||||||
|         checkBaseReadPrivilege(); |         checkBaseReadPrivilege(institutionId); | ||||||
|         return this.paginationService.getPage( |         return this.paginationService.getPage( | ||||||
|                 pageNumber, |                 pageNumber, | ||||||
|                 pageSize, |                 pageSize, | ||||||
|                 sortBy, |                 sortBy, | ||||||
|                 sortOrder, |                 sortOrder, | ||||||
|                 UserRecordDynamicSqlSupport.userRecord, |                 UserRecordDynamicSqlSupport.userRecord, | ||||||
|                 () -> _getAll(null, from, to, activityTypes, entityTypes)); |                 () -> _getAll(institutionId, null, from, to, activityTypes, entityTypes)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @RequestMapping(path = "/page/{userId}", method = RequestMethod.GET) |     @RequestMapping(path = "/page/{userId}", method = RequestMethod.GET) | ||||||
|     public Page<UserActivityLog> getPageForUser( |     public Page<UserActivityLog> getPageForUser( | ||||||
|             @PathVariable final String userId, |             @PathVariable final String userId, | ||||||
|             @RequestParam(required = false) final Long from, |             @RequestParam( | ||||||
|             @RequestParam(required = false) final Long to, |                     name = UserActivityLog.FILTER_ATTR_INSTITUTION, | ||||||
|             @RequestParam(required = false) final String activityTypes, |                     required = true, | ||||||
|             @RequestParam(required = false) final String entityTypes, |                     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_NUMBER, required = false) final Integer pageNumber, | ||||||
|             @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize, |             @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_BY, required = false) final String sortBy, | ||||||
|             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { |             @RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) { | ||||||
| 
 | 
 | ||||||
|         checkBaseReadPrivilege(); |         checkBaseReadPrivilege(institutionId); | ||||||
|         return this.paginationService.getPage( |         return this.paginationService.getPage( | ||||||
|                 pageNumber, |                 pageNumber, | ||||||
|                 pageSize, |                 pageSize, | ||||||
|                 sortBy, |                 sortBy, | ||||||
|                 sortOrder, |                 sortOrder, | ||||||
|                 UserRecordDynamicSqlSupport.userRecord, |                 UserRecordDynamicSqlSupport.userRecord, | ||||||
|                 () -> _getAll(userId, from, to, activityTypes, entityTypes)); |                 () -> _getAll(institutionId, userId, from, to, activityTypes, entityTypes)); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private void checkBaseReadPrivilege() { |  | ||||||
|         this.authorizationGrantService.checkHasAnyPrivilege( |  | ||||||
|                 EntityType.USER_ACTIVITY_LOG, |  | ||||||
|                 PrivilegeType.READ_ONLY); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Collection<UserActivityLog> _getAll( |     private Collection<UserActivityLog> _getAll( | ||||||
|  |             final Long institutionId, | ||||||
|             final String userId, |             final String userId, | ||||||
|             final Long from, |             final String from, | ||||||
|             final Long to, |             final String to, | ||||||
|             final String activityTypes, |             final String activityTypes, | ||||||
|             final String entityTypes) { |             final String entityTypes) { | ||||||
| 
 | 
 | ||||||
|  | @ -142,24 +177,32 @@ public class UserActivityLogController { | ||||||
|                         Arrays.asList(StringUtils.split(entityTypes, Constants.LIST_SEPARATOR)))) |                         Arrays.asList(StringUtils.split(entityTypes, Constants.LIST_SEPARATOR)))) | ||||||
|                 : null; |                 : 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 -> { |                     return true; | ||||||
|                 if (_activityTypes != null && !_activityTypes.contains(record.getActivityType())) { |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
|                 if (_entityTypes != null && !_entityTypes.contains(record.getEntityType())) { |  | ||||||
|                     return false; |  | ||||||
|                 } |                 } | ||||||
|  |                 : record -> true; | ||||||
| 
 | 
 | ||||||
|                 return true; |         return this.userActivityLogDAO.all( | ||||||
|             }).getOrThrow(); |                 institutionId, | ||||||
|  |                 userId, | ||||||
|  |                 Utils.toMilliSeconds(from), | ||||||
|  |                 Utils.toMilliSeconds(to), | ||||||
|  |                 filter).getOrThrow(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         } else { |     private void checkBaseReadPrivilege(final Long institutionId) { | ||||||
| 
 |         this.authorizationGrantService.checkPrivilege( | ||||||
|             return this.userActivityLogDAO.all(userId, from, to, record -> true) |                 EntityType.USER_ACTIVITY_LOG, | ||||||
|                     .getOrThrow(); |                 PrivilegeType.READ_ONLY, | ||||||
|         } |                 institutionId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -99,4 +99,12 @@ public abstract class AdministrationAPIIntegrationTest { | ||||||
|         return obtainAccessToken("examAdmin1", "admin"); |         return obtainAccessToken("examAdmin1", "admin"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | //    protected static class TestHelper { | ||||||
|  | // | ||||||
|  | //        private Supplier<String> accessTokenSuplier; | ||||||
|  | //        private String query; | ||||||
|  | //        private String endpoint; | ||||||
|  | //        private Object | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ import java.util.NoSuchElementException; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
| 
 | 
 | ||||||
|  | import org.joda.time.DateTime; | ||||||
| import org.joda.time.DateTimeZone; | import org.joda.time.DateTimeZone; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import org.springframework.http.MediaType; | import org.springframework.http.MediaType; | ||||||
|  | @ -28,7 +29,10 @@ import org.springframework.test.context.jdbc.Sql; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | 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.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.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
|  | @ -113,6 +117,15 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 contentAsString); |                 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 |     @Test | ||||||
|     public void getAllUserInfoNoFilter() throws Exception { |     public void getAllUserInfoNoFilter() throws Exception { | ||||||
|         String token = getSebAdminAccess(); |         String token = getSebAdminAccess(); | ||||||
|  | @ -126,34 +139,65 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
| 
 | 
 | ||||||
|         // expecting all users for a SEBAdmin except inactive. |         // expecting all users for a SEBAdmin except inactive. | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 7); |         assertTrue(userInfos.size() == 3); | ||||||
|         assertNotNull(getUserInfo("admin", userInfos)); |         assertNotNull(getUserInfo("admin", userInfos)); | ||||||
|         assertNotNull(getUserInfo("inst1Admin", userInfos)); |         assertNotNull(getUserInfo("inst1Admin", userInfos)); | ||||||
|         assertNotNull(getUserInfo("examSupporter", 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( |         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)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<List<UserInfo>>() { |                 new TypeReference<List<UserInfo>>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         // expecting all users of institution 1 for Institutional Admin of institution 1 |  | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 3); |         assertTrue(userInfos.size() == 3); | ||||||
|         assertNotNull(getUserInfo("admin", userInfos)); |         assertNotNull(getUserInfo("inst2Admin", userInfos)); | ||||||
|         assertNotNull(getUserInfo("inst1Admin", userInfos)); |         assertNotNull(getUserInfo("examAdmin1", userInfos)); | ||||||
|         assertNotNull(getUserInfo("examSupporter", 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 |     @Test | ||||||
|     public void getPageNoFilterNoPageAttributes() throws Exception { |     public void getPageNoFilterNoPageAttributes() throws Exception { | ||||||
|  | 
 | ||||||
|  |         // expecting all user accounts of the institution of SEBAdmin | ||||||
|  | 
 | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page") |                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page") | ||||||
|  | @ -166,15 +210,18 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 1); |         assertTrue(userInfos.numberOfPages == 1); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 7); |         assertTrue(userInfos.content.size() == 3); | ||||||
|         assertEquals("[user1, user2, user3, user4, user5, user6, user7]", getOrderedUUIDs(userInfos.content)); |         assertEquals("[user1, user2, user5]", getOrderedUUIDs(userInfos.content)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception { |     public void getPageNoFilterNoPageAttributesFromOtherInstitution() throws Exception { | ||||||
|  | 
 | ||||||
|  |         // expecting all user accounts of institution 2 | ||||||
|  | 
 | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         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)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -184,8 +231,26 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 1); |         assertTrue(userInfos.numberOfPages == 1); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 7); |         assertTrue(userInfos.content.size() == 4); | ||||||
|         assertEquals("[user7, user6, user5, user4, user3, user2, user1]", getOrderedUUIDs(userInfos.content)); |         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 |     @Test | ||||||
|  | @ -195,24 +260,25 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         // first page default sort order |         // first page default sort order | ||||||
|         Page<UserInfo> userInfos = this.jsonMapper.readValue( |         Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/page?pageNumber=1&pageSize=3") |                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 + "/page?page_number=1&page_size=3&institution=2") | ||||||
|  |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<Page<UserInfo>>() { |                 new TypeReference<Page<UserInfo>>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 3); |         assertTrue(userInfos.numberOfPages == 2); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 3); |         assertTrue(userInfos.content.size() == 3); | ||||||
|         assertEquals("[user1, user2, user3]", getOrderedUUIDs(userInfos.content)); |         assertEquals("[user3, user4, user6]", getOrderedUUIDs(userInfos.content)); | ||||||
| 
 | 
 | ||||||
|         // second page default sort order |         // second page default sort order | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .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)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -220,16 +286,17 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 3); |         assertTrue(userInfos.numberOfPages == 2); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 3); |         assertTrue(userInfos.pageSize == 1); | ||||||
|         assertEquals("[user4, user5, user6]", getOrderedUUIDs(userInfos.content)); |         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( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .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)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -237,7 +304,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 3); |         assertTrue(userInfos.numberOfPages == 2); | ||||||
|  |         assertTrue(userInfos.pageNumber == 2); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 1); |         assertTrue(userInfos.content.size() == 1); | ||||||
|         assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); |         assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); | ||||||
|  | @ -246,7 +314,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .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)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -254,10 +322,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.numberOfPages == 3); |         assertTrue(userInfos.numberOfPages == 2); | ||||||
|         assertNotNull(userInfos.content); |         assertNotNull(userInfos.content); | ||||||
|         assertTrue(userInfos.content.size() == 3); |         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) { |     private String getOrderedUUIDs(final Collection<UserInfo> list) { | ||||||
|  | @ -280,15 +348,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 7); |         assertTrue(userInfos.size() == 3); | ||||||
|         assertNotNull(getUserInfo("deactivatedUser", userInfos)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void getAllUserInfoWithOnlyActice() throws Exception { |     public void getAllUserInfoWithOnlyActive() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final List<UserInfo> userInfos = this.jsonMapper.readValue( |         final List<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true") |                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true&institution=2") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -296,14 +363,16 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 6); |         assertTrue(userInfos.size() == 3); | ||||||
|         assertNull(getUserInfo("deactivatedUser", userInfos)); |         assertNull(getUserInfo("deactivatedUser", userInfos)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void getAllUserInfoOnlyInactive() throws Exception { |     public void getAllUserInfoOnlyInactive() throws Exception { | ||||||
|  | 
 | ||||||
|  |         // expecting none for SEBAdmins institution | ||||||
|         final String token = getSebAdminAccess(); |         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") |                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -311,6 +380,18 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 new TypeReference<List<UserInfo>>() { |                 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); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 1); |         assertTrue(userInfos.size() == 1); | ||||||
|         assertNotNull(getUserInfo("deactivatedUser", userInfos)); |         assertNotNull(getUserInfo("deactivatedUser", userInfos)); | ||||||
|  | @ -328,8 +409,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(userInfos); |         assertNotNull(userInfos); | ||||||
|         assertTrue(userInfos.size() == 2); |         assertTrue(userInfos.size() == 1); | ||||||
|         assertNotNull(getUserInfo("examAdmin1", userInfos)); |  | ||||||
|         assertNotNull(getUserInfo("examSupporter", userInfos)); |         assertNotNull(getUserInfo("examSupporter", userInfos)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -381,8 +461,9 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         // check user activity log for newly created user |         // check user activity log for newly created user | ||||||
|         final List<UserActivityLog> logs = this.jsonMapper.readValue( |         final List<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user1?activityTypes=CREATE") |                         .perform( | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user1?activity_types=CREATE") | ||||||
|  |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<List<UserActivityLog>>() { |                 new TypeReference<List<UserActivityLog>>() { | ||||||
|  | @ -700,7 +781,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void deactivateUserAccount() throws Exception { |     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 |         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account | ||||||
|         final String examAdminToken = getExamAdmin1(); |         final String examAdminToken = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/deactivate") |         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 |         // With SEB Administrator it should work | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         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") |                 this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/deactivate") | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .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>() { |                 new TypeReference<UserInfo>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(deactivatedUser); |         assertNotNull(user); | ||||||
|         assertFalse(deactivatedUser.isActive()); |         assertFalse(user.isActive()); | ||||||
| 
 | 
 | ||||||
|         // check also user activity log |         // check also user activity log | ||||||
|         final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue( |         final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue( | ||||||
|  | @ -738,7 +835,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void activateUserAccount() throws Exception { |     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 |         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account | ||||||
|         final String examAdminToken = getExamAdmin1(); |         final String examAdminToken = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/activate") |         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 |         // With SEB Administrator it should work | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         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") |                 this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/activate") | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .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>() { |                 new TypeReference<UserInfo>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(activatedUser); |         assertNotNull(user); | ||||||
|         assertTrue(activatedUser.isActive()); |         assertTrue(user.isActive()); | ||||||
| 
 | 
 | ||||||
|         // check also user activity log |         // check also user activity log | ||||||
|         final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue( |         final Collection<UserActivityLog> userLogs = this.jsonMapper.readValue( | ||||||
|  |  | ||||||
|  | @ -8,18 +8,19 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.integration.api; | package ch.ethz.seb.sebserver.webservice.integration.api; | ||||||
| 
 | 
 | ||||||
| import static org.junit.Assert.assertNotNull; | import static org.junit.Assert.*; | ||||||
| import static org.junit.Assert.assertTrue; |  | ||||||
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||||||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
|  | import org.joda.time.DateTime; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import org.springframework.test.context.jdbc.Sql; | import org.springframework.test.context.jdbc.Sql; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | 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.gbl.model.user.UserActivityLog; | ||||||
| import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI; | import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI; | ||||||
| 
 | 
 | ||||||
|  | @ -38,14 +39,15 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(logs); |         assertNotNull(logs); | ||||||
|         assertTrue(5 == logs.size()); |         assertTrue(2 == logs.size()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void getAllAsSEBAdminForUser() throws Exception { |     public void getAllAsSEBAdminForUser() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|  |         // for a user in another institution, the institution has to be defined | ||||||
|         List<UserActivityLog> logs = this.jsonMapper.readValue( |         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)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -55,6 +57,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         assertNotNull(logs); |         assertNotNull(logs); | ||||||
|         assertTrue(2 == logs.size()); |         assertTrue(2 == logs.size()); | ||||||
| 
 | 
 | ||||||
|  |         // for a user in the same institution no institution is needed | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user2") |                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/user2") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|  | @ -69,47 +72,18 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void getAllAsSEBAdminInTimeRange() throws Exception { |     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(); |         final String token = getSebAdminAccess(); | ||||||
|         List<UserActivityLog> logs = this.jsonMapper.readValue( |         List<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?from=2") |                 this.mockMvc.perform( | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + sec2) | ||||||
|                         .andExpect(status().isOk()) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .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)) |  | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<List<UserActivityLog>>() { |                 new TypeReference<List<UserActivityLog>>() { | ||||||
|  | @ -120,8 +94,8 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
| 
 | 
 | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?activityTypes=CREATE,MODIFY") |                                 + sec2 + "&to=" + sec4) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -129,7 +103,77 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(logs); |         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 |     @Test | ||||||
|  | @ -137,7 +181,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         List<UserActivityLog> logs = this.jsonMapper.readValue( |         List<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 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)) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -151,7 +195,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?entityTypes=INSTITUTION,EXAM") |                                         + "?entity_types=INSTITUTION,EXAM") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -159,7 +203,21 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTest { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(logs); |         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 |     @Test | ||||||
|  |  | ||||||
|  | @ -24,10 +24,10 @@ INSERT INTO user_role VALUES | ||||||
|     ; |     ; | ||||||
|      |      | ||||||
| INSERT INTO user_activity_log VALUES | INSERT INTO user_activity_log VALUES | ||||||
|     (1, 'user1', 1, 'MODIFY', 'INSTITUTION', '1', 'some message'), |     (1, 'user1', 1000, 'MODIFY', 'INSTITUTION', '1', 'some message'), | ||||||
|     (2, 'user2', 2, 'CREATE', 'EXAM', '1', 'some message'), |     (2, 'user2', 2000, 'CREATE', 'EXAM', '1', 'some message'), | ||||||
|     (3, 'user3', 3, 'CREATE', 'EXAM', '2', 'some message'), |     (3, 'user3', 3000, 'CREATE', 'EXAM', '2', 'some message'), | ||||||
|     (4, 'user4', 4, 'CREATE', 'EXAM', '33', 'some message'), |     (4, 'user4', 4000, 'CREATE', 'EXAM', '33', 'some message'), | ||||||
|     (5, 'user4', 5, 'MODIFY', 'EXAM', '33', 'some message') |     (5, 'user4', 5000, 'MODIFY', 'EXAM', '33', 'some message') | ||||||
|     ; |     ; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti