From 8e9cf8741dfbc118b945e1b1ec25b1e54e15932d Mon Sep 17 00:00:00 2001 From: anhefti Date: Sat, 26 Jan 2019 17:52:05 +0100 Subject: [PATCH] adjust API and tests and bugfix --- .../ch/ethz/seb/sebserver/gbl/POSTMapper.java | 120 ++++++++ .../ethz/seb/sebserver/gbl/model/Entity.java | 2 +- .../seb/sebserver/gbl/model/exam/Exam.java | 19 ++ .../gbl/model/institution/Institution.java | 9 + .../gbl/model/institution/LmsSetup.java | 15 + .../seb/sebserver/gbl/model/user/UserMod.java | 17 ++ .../ethz/seb/sebserver/gbl/util/Result.java | 6 +- .../ch/ethz/seb/sebserver/gbl/util/Utils.java | 16 ++ .../servicelayer/dao/EntityDAO.java | 10 +- .../servicelayer/dao/FilterMap.java | 66 +---- .../servicelayer/dao/InstitutionDAO.java | 2 + .../servicelayer/dao/impl/ExamDAOImpl.java | 110 ++++---- .../dao/impl/IndicatorDAOImpl.java | 106 ++++--- .../dao/impl/InstitutionDAOImpl.java | 91 +++--- .../dao/impl/LmsSetupDAOImpl.java | 98 +++---- .../dao/impl/UserActivityLogDAOImpl.java | 12 +- .../servicelayer/dao/impl/UserDaoImpl.java | 122 ++++---- .../validation/BeanValidationService.java | 51 +--- .../webservice/weblayer/api/APIParamsMap.java | 75 ----- .../weblayer/api/EntityController.java | 265 ++++++++++-------- .../api/ExamAdministrationController.java | 201 ++++++++----- .../weblayer/api/InstitutionController.java | 10 + .../weblayer/api/LmsSetupController.java | 6 + .../weblayer/api/QuizImportController.java | 27 -- .../weblayer/api/UserAccountController.java | 10 +- .../config/application-dev-ws.properties | 5 +- .../api/admin/InstitutionAPITest.java | 23 +- .../integration/api/admin/UserAPITest.java | 207 ++++++++------ .../api/admin/UserActivityLogAPITest.java | 24 +- 29 files changed, 940 insertions(+), 785 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/gbl/POSTMapper.java delete mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIParamsMap.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/POSTMapper.java b/src/main/java/ch/ethz/seb/sebserver/gbl/POSTMapper.java new file mode 100644 index 00000000..c9e4901a --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/POSTMapper.java @@ -0,0 +1,120 @@ +/* + * 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.gbl; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.apache.commons.lang3.BooleanUtils; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.springframework.util.MultiValueMap; + +import ch.ethz.seb.sebserver.gbl.util.Utils; + +public class POSTMapper { + + protected final MultiValueMap params; + + public POSTMapper(final MultiValueMap params) { + super(); + this.params = params; + } + + public String getString(final String name) { + return this.params.getFirst(name); + } + + public Long getLong(final String name) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + + return Long.parseLong(value); + } + + public Integer getInteger(final String name) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + + return Integer.parseInt(value); + } + + public Locale getLocale(final String name) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + + return Locale.forLanguageTag(value); + } + + public boolean getBoolean(final String name) { + return BooleanUtils.toBoolean(this.params.getFirst(name)); + } + + public Boolean getBooleanObject(final String name) { + return BooleanUtils.toBooleanObject(this.params.getFirst(name)); + } + + public Integer getBooleanAsInteger(final String name) { + final Boolean booleanObject = getBooleanObject(name); + if (booleanObject == null) { + return null; + } + return BooleanUtils.toIntegerObject(booleanObject); + } + + public DateTimeZone getDateTimeZone(final String name) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + try { + return DateTimeZone.forID(value); + } catch (final Exception e) { + return null; + } + } + + public Set getStringSet(final String name) { + final List list = this.params.get(name); + if (list == null) { + return Collections.emptySet(); + } + return Utils.immutableSetOf(list); + } + + public > T getEnum(final String name, final Class type) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + try { + return Enum.valueOf(type, value); + } catch (final Exception e) { + return null; + } + } + + public DateTime getDateTime(final String name) { + final String value = this.params.getFirst(name); + if (value == null) { + return null; + } + + return Utils.toDateTime(value); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java index d96aa5b3..5cbb2df3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; public interface Entity extends ModelIdAware { - public static final String FILTER_ATTR_INSTITUTION = "institution"; + public static final String FILTER_ATTR_INSTITUTION = Domain.ATTR_INSTITUTION_ID; public static final String FILTER_ATTR_ACTIVE = "active"; public static final String FILTER_ATTR_NAME = "name"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/Exam.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/Exam.java index 5cf887e6..787e87a2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/Exam.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/Exam.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Activatable; import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; import ch.ethz.seb.sebserver.gbl.model.EntityType; @@ -133,6 +134,24 @@ public final class Exam implements GrantEntity, Activatable { : Collections.emptyList(); } + public Exam(final String modelId, final QuizData quizData, final POSTMapper mapper) { + + this.id = (modelId != null) ? Long.parseLong(modelId) : null; + this.institutionId = mapper.getLong(EXAM.ATTR_INSTITUTION_ID); + this.lmsSetupId = mapper.getLong(EXAM.ATTR_LMS_SETUP_ID); + this.externalId = mapper.getString(EXAM.ATTR_EXTERNAL_ID); + this.name = quizData.name; + this.description = quizData.description; + this.status = mapper.getEnum(EXAM.ATTR_STATUS, ExamStatus.class); + this.startTime = quizData.startTime; + this.endTime = quizData.endTime; + this.startURL = mapper.getString(EXAM.ATTR_INSTITUTION_ID); + this.type = mapper.getEnum(EXAM.ATTR_TYPE, ExamType.class); + this.owner = mapper.getString(EXAM.ATTR_OWNER); + this.active = mapper.getBooleanObject(EXAM.ATTR_ACTIVE); + this.supporter = mapper.getStringSet(EXAM.ATTR_SUPPORTER); + } + @Override public EntityType entityType() { return EntityType.EXAM; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java index c55d28b2..d20f1984 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java @@ -13,6 +13,7 @@ import javax.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Activatable; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; @@ -53,6 +54,14 @@ public final class Institution implements GrantEntity, Activatable { this.active = active; } + public Institution(final String modelId, final POSTMapper mapper) { + this.id = (modelId != null) ? Long.parseLong(modelId) : null; + this.name = mapper.getString(INSTITUTION.ATTR_NAME); + this.urlSuffix = mapper.getString(INSTITUTION.ATTR_URL_SUFFIX); + this.logoImage = mapper.getString(INSTITUTION.ATTR_LOGO_IMAGE); + this.active = mapper.getBooleanObject(INSTITUTION.ATTR_ACTIVE); + } + @Override public EntityType entityType() { return EntityType.INSTITUTION; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java index e251e80b..11a72fd7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Activatable; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; @@ -103,6 +104,20 @@ public final class LmsSetup implements GrantEntity, Activatable { this.active = (active != null) ? active : Boolean.FALSE; } + public LmsSetup(final String modelId, final POSTMapper mapper) { + this.id = (modelId != null) ? Long.parseLong(modelId) : null; + this.institutionId = mapper.getLong(LMS_SETUP.ATTR_INSTITUTION_ID); + this.name = mapper.getString(LMS_SETUP.ATTR_NAME); + this.lmsType = mapper.getEnum(LMS_SETUP.ATTR_LMS_TYPE, LmsType.class); + this.lmsAuthName = mapper.getString(LMS_SETUP.ATTR_LMS_CLIENTNAME); + this.lmsAuthSecret = mapper.getString(LMS_SETUP.ATTR_LMS_CLIENTSECRET); + this.lmsApiUrl = mapper.getString(LMS_SETUP.ATTR_LMS_URL); + this.lmsRestApiToken = mapper.getString(LMS_SETUP.ATTR_LMS_REST_API_TOKEN); + this.sebAuthName = mapper.getString(LMS_SETUP.ATTR_SEB_CLIENTNAME); + this.sebAuthSecret = mapper.getString(LMS_SETUP.ATTR_SEB_CLIENTSECRET); + this.active = mapper.getBooleanObject(LMS_SETUP.ATTR_ACTIVE); + } + @Override public EntityType entityType() { return EntityType.LMS_SETUP; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java index d3f51fa5..2932d287 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Domain.USER; import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; import ch.ethz.seb.sebserver.gbl.model.EntityType; @@ -46,6 +47,7 @@ public final class UserMod implements GrantEntity { public final String name; /** The internal user name */ + @NotNull @Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}") @JsonProperty(USER.ATTR_USERNAME) public final String username; @@ -56,10 +58,12 @@ public final class UserMod implements GrantEntity { public final String email; /** The users locale */ + @NotNull @JsonProperty(USER.ATTR_LOCALE) public final Locale locale; /** The users time zone */ + @NotNull @JsonProperty(USER.ATTR_TIMEZONE) public final DateTimeZone timeZone; @@ -116,6 +120,19 @@ public final class UserMod implements GrantEntity { this.roles = userInfo.roles; } + public UserMod(final String modelId, final POSTMapper postAttrMapper) { + this.uuid = modelId; + this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID); + this.newPassword = postAttrMapper.getString(ATTR_NAME_NEW_PASSWORD); + this.retypedNewPassword = postAttrMapper.getString(ATTR_NAME_RETYPED_NEW_PASSWORD); + this.name = postAttrMapper.getString(USER.ATTR_NAME); + this.username = postAttrMapper.getString(USER.ATTR_USERNAME); + this.email = postAttrMapper.getString(USER.ATTR_EMAIL); + this.locale = postAttrMapper.getLocale(USER.ATTR_LOCALE); + this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE); + this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME); + } + @Override public String getModelId() { return this.uuid; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java index 28638ffa..5ac9e2b5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java @@ -119,7 +119,11 @@ public final class Result { public Result map(final Function mapf) { if (this.error == null) { try { - return Result.of(mapf.apply(this.value)); + final U result = mapf.apply(this.value); + if (result instanceof Result) { + throw new IllegalArgumentException("Use flatMap instead!"); + } + return Result.of(result); } catch (final Throwable t) { return Result.ofError(t); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java index 54cd9935..6cfc1aa5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -22,6 +22,9 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import ch.ethz.seb.sebserver.gbl.Constants; public final class Utils { @@ -139,4 +142,17 @@ public final class Utils { return toDateTime(dateString).getMillis(); } + public static String toJsonArray(final String string) { + if (string == null) { + return null; + } + + final List asList = Arrays.asList(StringUtils.split(string, Constants.LIST_SEPARATOR_CHAR)); + try { + return new ObjectMapper().writeValueAsString(asList); + } catch (final JsonProcessingException e) { + return string; + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java index 134da7d5..2733d622 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/EntityDAO.java @@ -79,15 +79,15 @@ public interface EntityDAO { }); } + Result createNew(M data); + /** Use this to save/modify an entity. - * If the model identifier from given modified entity data is null or not exists already, a new entity is created. - * If the model identifier is available and matches an existing entity, all entity data that are - * not null on modified entity data instance are updated within the existing entity. * - * @param modified modified data instance containing all data that should be modified + * @param modelId the model id of the entity to save + * @param data entity instance containing all data that should be saved * @return A Result of the entity instance where the successfully saved/modified entity data is available or a * reported exception on error case */ - Result save(M modified); + Result save(String modelId, M data); /** Use this to delete a set Entity by a Collection of EntityKey * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java index 30c9d2f6..c01f0416 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java @@ -8,27 +8,20 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; -import java.util.Locale; -import java.util.Map; - -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.LocaleUtils; import org.joda.time.DateTime; +import org.springframework.util.MultiValueMap; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; -import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.webservice.datalayer.batis.JodaTimeTypeResolver; -public class FilterMap { +public class FilterMap extends POSTMapper { - public final Map params; - - public FilterMap(final Map params) { - super(); - this.params = Utils.immutableMapOf(params); + public FilterMap(final MultiValueMap params) { + super(params); } public Integer getActiveAsInt() { @@ -95,55 +88,8 @@ public class FilterMap { return getSQLWildcard(Indicator.FILTER_ATTR_NAME); } - public String getString(final String name) { - return this.params.get(name); - } - public String getSQLWildcard(final String name) { - return toSQLWildcard(this.params.get(name)); - } - - public Long getLong(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return Long.parseLong(value); - } - - public Integer getInteger(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return Integer.parseInt(value); - } - - public Locale getLocale(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return LocaleUtils.toLocale(name); - } - - public boolean getBoolean(final String name) { - return BooleanUtils.toBoolean(this.params.get(name)); - } - - public Boolean getBooleanObject(final String name) { - return BooleanUtils.toBooleanObject(this.params.get(name)); - } - - public Integer getBooleanAsInteger(final String name) { - final Boolean booleanObject = getBooleanObject(name); - if (booleanObject == null) { - return null; - } - return BooleanUtils.toIntegerObject(booleanObject); + return toSQLWildcard(this.params.getFirst(name)); } public static String toSQLWildcard(final String text) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/InstitutionDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/InstitutionDAO.java index 7441382d..ccc4a75b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/InstitutionDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/InstitutionDAO.java @@ -14,4 +14,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSuppor public interface InstitutionDAO extends ActivatableEntityDAO, BulkActionSupportDAO { + boolean exists(String name); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index 7aa5143b..fb03ed72 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -157,18 +157,58 @@ public class ExamDAOImpl implements ExamDAO { @Override @Transactional - public Result save(final Exam exam) { - if (exam == null) { - return Result.ofError(new NullPointerException("exam has null-reference")); - } + public Result save(final String modelId, 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)); - return (exam.id == null) - ? insert(exam) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback) - : update(exam) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback); + this.examRecordMapper.updateByPrimaryKeySelective(examRecord); + return this.examRecordMapper.selectByPrimaryKey(exam.id); + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result createNew(final Exam exam) { + return Result.tryCatch(() -> { + + // fist check if it is not already existing + final List records = this.examRecordMapper.selectByExample() + .where(ExamRecordDynamicSqlSupport.lmsSetupId, isEqualTo(exam.lmsSetupId)) + .and(ExamRecordDynamicSqlSupport.externalId, isEqualTo(exam.externalId)) + .build() + .execute(); + + // if there is already an existing imported exam for the quiz, this is returned + if (records != null && records.size() > 0) { + return records.get(0); + } + + final ExamRecord examRecord = new ExamRecord( + null, + exam.institutionId, + exam.lmsSetupId, + exam.externalId, + this.userService.getCurrentUser().uuid(), + null, + null, + null, + BooleanUtils.toInteger(false)); + + this.examRecordMapper.updateByPrimaryKeySelective(examRecord); + return this.examRecordMapper.selectByPrimaryKey(exam.id); + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); } @Override @@ -237,54 +277,6 @@ public class ExamDAOImpl implements ExamDAO { }).flatMap(this::toDomainModel); } - private Result insert(final Exam exam) { - return Result.tryCatch(() -> { - - // fist check if it is not already existing - final List records = this.examRecordMapper.selectByExample() - .where(ExamRecordDynamicSqlSupport.lmsSetupId, isEqualTo(exam.lmsSetupId)) - .and(ExamRecordDynamicSqlSupport.externalId, isEqualTo(exam.externalId)) - .build() - .execute(); - - // if there is already an existing imported exam for the quiz, this is returned - if (records != null && records.size() > 0) { - return records.get(0); - } - - final ExamRecord examRecord = new ExamRecord( - null, - exam.institutionId, - exam.lmsSetupId, - exam.externalId, - this.userService.getCurrentUser().uuid(), - null, - null, - null, - BooleanUtils.toInteger(false)); - - this.examRecordMapper.updateByPrimaryKeySelective(examRecord); - return this.examRecordMapper.selectByPrimaryKey(exam.id); - }); - } - - private Result 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); - }); - } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { return Result.tryCatch(() -> { return this.examRecordMapper.selectIdsByExample() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java index 2ef0f921..ae9f67b3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java @@ -143,18 +143,56 @@ public class IndicatorDAOImpl implements IndicatorDAO { @Override @Transactional - public Result save(final Indicator modified) { - if (modified == null) { - return Result.ofError(new NullPointerException("Indicator has null-reference")); - } + public Result save(final String modelId, final Indicator modified) { + return Result.tryCatch(() -> { - return (modified.id != null) - ? update(modified) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback) - : createNew(modified) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback); + final IndicatorRecord newRecord = new IndicatorRecord( + modified.id, + null, + modified.type.name(), + modified.name, + modified.defaultColor); + + this.indicatorRecordMapper.updateByPrimaryKeySelective(newRecord); + + // update also the thresholds + this.thresholdRecordMapper.deleteByExample() + .where(ThresholdRecordDynamicSqlSupport.indicatorId, isEqualTo(modified.id)) + .build() + .execute(); + + modified.thresholds + .stream() + .map(threshold -> new ThresholdRecord( + null, + modified.id, + new BigDecimal(threshold.value), + threshold.color)) + .forEach(this.thresholdRecordMapper::insert); + + return this.indicatorRecordMapper.selectByPrimaryKey(modified.id); + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result createNew(final Indicator modified) { + return Result.tryCatch(() -> { + + final IndicatorRecord newRecord = new IndicatorRecord( + null, + modified.examId, + modified.type.name(), + modified.name, + modified.defaultColor); + + this.indicatorRecordMapper.insert(newRecord); + return newRecord; + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); } @Override @@ -263,50 +301,4 @@ public class IndicatorDAOImpl implements IndicatorDAO { } - private Result createNew(final Indicator indicator) { - return Result.tryCatch(() -> { - - final IndicatorRecord newRecord = new IndicatorRecord( - null, - indicator.examId, - indicator.type.name(), - indicator.name, - indicator.defaultColor); - - this.indicatorRecordMapper.insert(newRecord); - return newRecord; - }); - } - - private Result update(final Indicator indicator) { - return Result.tryCatch(() -> { - - final IndicatorRecord newRecord = new IndicatorRecord( - indicator.id, - null, - indicator.type.name(), - indicator.name, - indicator.defaultColor); - - this.indicatorRecordMapper.updateByPrimaryKeySelective(newRecord); - - // update also the thresholds - this.thresholdRecordMapper.deleteByExample() - .where(ThresholdRecordDynamicSqlSupport.indicatorId, isEqualTo(indicator.id)) - .build() - .execute(); - - indicator.thresholds - .stream() - .map(threshold -> new ThresholdRecord( - null, - indicator.id, - new BigDecimal(threshold.value), - threshold.color)) - .forEach(this.thresholdRecordMapper::insert); - - return this.indicatorRecordMapper.selectByPrimaryKey(indicator.id); - }); - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java index e18a5008..e70a0d38 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java @@ -8,8 +8,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl; -import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent; -import static org.mybatis.dynamic.sql.SqlBuilder.isIn; +import static org.mybatis.dynamic.sql.SqlBuilder.*; import java.util.Collection; import java.util.Collections; @@ -19,6 +18,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter; import org.mybatis.dynamic.sql.select.QueryExpressionDSL; @@ -55,6 +55,21 @@ public class InstitutionDAOImpl implements InstitutionDAO { return EntityType.INSTITUTION; } + @Override + @Transactional(readOnly = true) + public boolean exists(final String name) { + if (StringUtils.isBlank(name)) { + return false; + } + + final Long count = this.institutionRecordMapper.countByExample() + .where(InstitutionRecordDynamicSqlSupport.name, isEqualTo(name)) + .build() + .execute(); + + return count != null && count.longValue() > 0; + } + @Override @Transactional(readOnly = true) public Result byPK(final Long id) { @@ -113,18 +128,39 @@ public class InstitutionDAOImpl implements InstitutionDAO { @Override @Transactional - public Result save(final Institution institution) { - if (institution == null) { - return Result.ofError(new NullPointerException("institution has null-reference")); - } + public Result save(final String modelId, final Institution institution) { + return Result.tryCatch(() -> { - return (institution.id != null) - ? update(institution) - .flatMap(InstitutionDAOImpl::toDomainModel) - .onErrorDo(TransactionHandler::rollback) - : createNew(institution) - .flatMap(InstitutionDAOImpl::toDomainModel) - .onErrorDo(TransactionHandler::rollback); + final InstitutionRecord newRecord = new InstitutionRecord( + institution.id, + institution.name, + institution.urlSuffix, + null, + institution.logoImage); + + this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord); + return this.institutionRecordMapper.selectByPrimaryKey(institution.id); + }) + .flatMap(InstitutionDAOImpl::toDomainModel) + .onErrorDo(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result createNew(final Institution institution) { + return Result.tryCatch(() -> { + final InstitutionRecord newRecord = new InstitutionRecord( + null, + institution.name, + institution.urlSuffix, + BooleanUtils.toInteger(false), + institution.logoImage); + + this.institutionRecordMapper.insert(newRecord); + return newRecord; + }) + .flatMap(InstitutionDAOImpl::toDomainModel) + .onErrorDo(TransactionHandler::rollback); } @Override @@ -201,35 +237,6 @@ public class InstitutionDAOImpl implements InstitutionDAO { }); } - private Result createNew(final Institution institution) { - return Result.tryCatch(() -> { - final InstitutionRecord newRecord = new InstitutionRecord( - null, - institution.name, - institution.urlSuffix, - BooleanUtils.toInteger(false), - institution.logoImage); - - this.institutionRecordMapper.insert(newRecord); - return newRecord; - }); - } - - private Result update(final Institution institution) { - return Result.tryCatch(() -> { - - final InstitutionRecord newRecord = new InstitutionRecord( - institution.id, - institution.name, - institution.urlSuffix, - null, - institution.logoImage); - - this.institutionRecordMapper.updateByPrimaryKeySelective(newRecord); - return this.institutionRecordMapper.selectByPrimaryKey(institution.id); - }); - } - private static Result toDomainModel(final InstitutionRecord record) { return Result.tryCatch(() -> new Institution( record.getId(), diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java index 0dbdf33d..0137e9fe 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java @@ -121,18 +121,52 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { @Override @Transactional - public Result save(final LmsSetup lmsSetup) { - if (lmsSetup == null) { - return Result.ofError(new NullPointerException("lmsSetup has null-reference")); - } + public Result save(final String modelId, final LmsSetup lmsSetup) { + return Result.tryCatch(() -> { - return (lmsSetup.id != null) - ? update(lmsSetup) - .flatMap(LmsSetupDAOImpl::toDomainModel) - .onErrorDo(TransactionHandler::rollback) - : createNew(lmsSetup) - .flatMap(LmsSetupDAOImpl::toDomainModel) - .onErrorDo(TransactionHandler::rollback); + final LmsSetupRecord newRecord = new LmsSetupRecord( + lmsSetup.id, + lmsSetup.institutionId, + lmsSetup.name, + (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, + lmsSetup.lmsApiUrl, + lmsSetup.lmsAuthName, + lmsSetup.lmsAuthSecret, + lmsSetup.lmsRestApiToken, + lmsSetup.sebAuthName, + lmsSetup.sebAuthSecret, + null); + + this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord); + return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id); + }) + .flatMap(LmsSetupDAOImpl::toDomainModel) + .onErrorDo(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result createNew(final LmsSetup lmsSetup) { + return Result.tryCatch(() -> { + + final LmsSetupRecord newRecord = new LmsSetupRecord( + null, + lmsSetup.institutionId, + lmsSetup.name, + (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, + lmsSetup.lmsApiUrl, + lmsSetup.lmsAuthName, + lmsSetup.lmsAuthSecret, + lmsSetup.lmsRestApiToken, + lmsSetup.sebAuthName, + lmsSetup.sebAuthSecret, + BooleanUtils.toInteger(false)); + + this.lmsSetupRecordMapper.insert(newRecord); + return newRecord; + }) + .flatMap(LmsSetupDAOImpl::toDomainModel) + .onErrorDo(TransactionHandler::rollback); } @Override @@ -242,46 +276,4 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { BooleanUtils.toBooleanObject(record.getActive()))); } - private Result createNew(final LmsSetup lmsSetup) { - return Result.tryCatch(() -> { - - final LmsSetupRecord newRecord = new LmsSetupRecord( - null, - lmsSetup.institutionId, - lmsSetup.name, - (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, - lmsSetup.lmsApiUrl, - lmsSetup.lmsAuthName, - lmsSetup.lmsAuthSecret, - lmsSetup.lmsRestApiToken, - lmsSetup.sebAuthName, - lmsSetup.sebAuthSecret, - BooleanUtils.toInteger(false)); - - this.lmsSetupRecordMapper.insert(newRecord); - return newRecord; - }); - } - - private Result update(final LmsSetup lmsSetup) { - return Result.tryCatch(() -> { - - final LmsSetupRecord newRecord = new LmsSetupRecord( - lmsSetup.id, - lmsSetup.institutionId, - lmsSetup.name, - (lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null, - lmsSetup.lmsApiUrl, - lmsSetup.lmsAuthName, - lmsSetup.lmsAuthSecret, - lmsSetup.lmsRestApiToken, - lmsSetup.sebAuthName, - lmsSetup.sebAuthSecret, - null); - - this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord); - return this.lmsSetupRecordMapper.selectByPrimaryKey(lmsSetup.id); - }); - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java index 40050873..e7b112c3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java @@ -317,14 +317,20 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { @Transactional(readOnly = true) public Result> loadEntities(final Collection keys) { // TODO Auto-generated method stub - return null; + return Result.ofTODO(); } @Override @Transactional - public Result save(final UserActivityLog modified) { + public Result save(final String modelId, final UserActivityLog modified) { // TODO Auto-generated method stub - return null; + return Result.ofTODO(); + } + + @Override + public Result createNew(final UserActivityLog data) { + // TODO Auto-generated method stub + return Result.ofTODO(); } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java index e987e8e1..7d645ffd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java @@ -176,18 +176,65 @@ public class UserDaoImpl implements UserDAO { @Override @Transactional - public Result save(final UserMod userMod) { - if (userMod == null) { - return Result.ofError(new NullPointerException("userMod has null-reference")); - } + public Result createNew(final UserMod userMod) { + return Result.tryCatch(() -> { - return (userMod.uuid != null) - ? updateUser(userMod) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback) - : createNewUser(userMod) - .flatMap(this::toDomainModel) - .onErrorDo(TransactionHandler::rollback); + if (!userMod.newPasswordMatch()) { + throw new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH); + } + + final UserRecord recordToSave = new UserRecord( + null, + userMod.institutionId, + UUID.randomUUID().toString(), + userMod.name, + userMod.username, + this.userPasswordEncoder.encode(userMod.getNewPassword()), + userMod.email, + userMod.locale.toLanguageTag(), + userMod.timeZone.getID(), + BooleanUtils.toInteger(false)); + + this.userRecordMapper.insert(recordToSave); + final Long newUserPK = recordToSave.getId(); + final UserRecord newRecord = this.userRecordMapper + .selectByPrimaryKey(newUserPK); + insertRolesForUser(newUserPK, userMod.roles); + return newRecord; + + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result save(final String modelId, final UserMod userMod) { + return recordByUUID(modelId) + .map(record -> { + final boolean changePWD = userMod.passwordChangeRequest(); + if (changePWD && !userMod.newPasswordMatch()) { + throw new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH); + } + + final UserRecord newRecord = new UserRecord( + record.getId(), + null, + null, + userMod.name, + userMod.username, + (changePWD) ? this.userPasswordEncoder.encode(userMod.getNewPassword()) : null, + userMod.email, + userMod.locale.toLanguageTag(), + userMod.timeZone.getID(), + null); + + this.userRecordMapper.updateByPrimaryKeySelective(newRecord); + updateRolesForUser(record.getId(), userMod.roles); + return this.userRecordMapper.selectByPrimaryKey(record.getId()); + }) + .flatMap(this::toDomainModel) + .onErrorDo(TransactionHandler::rollback); } @Override @@ -302,59 +349,6 @@ public class UserDaoImpl implements UserDAO { }); } - private Result updateUser(final UserMod userMod) { - return recordByUUID(userMod.uuid) - .map(record -> { - final boolean changePWD = userMod.passwordChangeRequest(); - if (changePWD && !userMod.newPasswordMatch()) { - throw new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH); - } - - final UserRecord newRecord = new UserRecord( - record.getId(), - null, - null, - userMod.name, - userMod.username, - (changePWD) ? this.userPasswordEncoder.encode(userMod.getNewPassword()) : null, - userMod.email, - userMod.locale.toLanguageTag(), - userMod.timeZone.getID(), - null); - - this.userRecordMapper.updateByPrimaryKeySelective(newRecord); - updateRolesForUser(record.getId(), userMod.roles); - return this.userRecordMapper.selectByPrimaryKey(record.getId()); - }); - } - - private Result createNewUser(final UserMod userMod) { - return Result.tryCatch(() -> { - - if (!userMod.newPasswordMatch()) { - throw new APIMessageException(ErrorMessage.PASSWORD_MISSMATCH); - } - - final UserRecord newRecord = new UserRecord( - null, - userMod.institutionId, - UUID.randomUUID().toString(), - userMod.name, - userMod.username, - this.userPasswordEncoder.encode(userMod.getNewPassword()), - userMod.email, - userMod.locale.toLanguageTag(), - userMod.timeZone.getID(), - BooleanUtils.toInteger(false)); - - this.userRecordMapper.insert(newRecord); - final Long newUserId = newRecord.getId(); - insertRolesForUser(newUserId, userMod.roles); - return newRecord; - - }); - } - private void updateRolesForUser(final Long userId, @NotNull final Set roles) { // first delete old roles this.roleRecordMapper.deleteByExample() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/BeanValidationService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/BeanValidationService.java index ecf6dab1..779b49d4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/BeanValidationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/BeanValidationService.java @@ -8,72 +8,31 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.validation; -import java.util.Map; - import org.springframework.stereotype.Service; import org.springframework.validation.DirectFieldBindingResult; import org.springframework.validation.Validator; -import com.fasterxml.jackson.databind.ObjectReader; - -import ch.ethz.seb.sebserver.gbl.JSONMapper; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Result; @Service @WebServiceProfile public class BeanValidationService { private final Validator validator; - private final JSONMapper jsonMapper; - - public BeanValidationService( - final Validator validator, - final JSONMapper jsonMapper) { + public BeanValidationService(final Validator validator) { this.validator = validator; - this.jsonMapper = jsonMapper; } - public void validateBean(final T bean) { + public Result validateBean(final T bean) { final DirectFieldBindingResult errors = new DirectFieldBindingResult(bean, ""); this.validator.validate(bean, errors); if (errors.hasErrors()) { - throw new BeanValidationException(errors); - } - } - - public M validateNewBean(final Map params, final Class type) { - M result = null; - try { - final String stringValue = this.jsonMapper.writeValueAsString(params); - result = this.jsonMapper.readValue(stringValue, type); - } catch (final Exception e) { - throw new RuntimeException("Unexpected error: ", e); + return Result.ofError(new BeanValidationException(errors)); } - if (result != null) { - validateBean(result); - } - return result; - } - - public M validateModifiedBean(final T bean, final Map params, final Class type) { - - M result = null; - try { - final String stringValue = this.jsonMapper.writeValueAsString(bean); - final String paramsString = this.jsonMapper.writeValueAsString(params); - result = this.jsonMapper.readValue(stringValue, type); - final ObjectReader updater = this.jsonMapper.readerForUpdating(result); - result = updater.readValue(paramsString); - } catch (final Exception e) { - throw new RuntimeException("Unexpected error: ", e); - } - - if (result != null) { - validateBean(result); - } - return result; + return Result.of(bean); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIParamsMap.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIParamsMap.java deleted file mode 100644 index 54272112..00000000 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIParamsMap.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.Locale; -import java.util.Map; - -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.LocaleUtils; - -import ch.ethz.seb.sebserver.gbl.util.Utils; - -public class APIParamsMap { - - public final Map params; - - public APIParamsMap(final Map params) { - super(); - this.params = Utils.immutableMapOf(params); - } - - public String getString(final String name) { - return this.params.get(name); - } - - public Long getLong(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return Long.parseLong(value); - } - - public Integer getInteger(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return Integer.parseInt(value); - } - - public Locale getLocale(final String name) { - final String value = this.params.get(name); - if (value == null) { - return null; - } - - return LocaleUtils.toLocale(name); - } - - public boolean getBoolean(final String name) { - return BooleanUtils.toBoolean(this.params.get(name)); - } - - public Boolean getBooleanObject(final String name) { - return BooleanUtils.toBooleanObject(this.params.get(name)); - } - - public Integer getBooleanAsInteger(final String name) { - final Boolean booleanObject = getBooleanObject(this.params.get(name)); - if (booleanObject == null) { - return null; - } - return BooleanUtils.toIntegerObject(booleanObject); - } - -} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java index 8f40010c..25d3c9f1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java @@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; import java.util.Arrays; import java.util.Collection; -import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -19,6 +18,7 @@ import javax.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlTable; import org.springframework.http.MediaType; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.PathVariable; @@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityKey; @@ -82,6 +83,10 @@ public abstract class EntityController allRequestParams) { + @RequestParam final MultiValueMap allRequestParams) { checkReadPrivilege(institutionId); final FilterMap filterMap = new FilterMap(allRequestParams); - allRequestParams.putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, String.valueOf(institutionId)); + allRequestParams.putIfAbsent( + Entity.FILTER_ATTR_INSTITUTION, + Arrays.asList(String.valueOf(institutionId))); return this.paginationService.getPage( pageNumber, @@ -110,17 +117,27 @@ public abstract class EntityController getAll(filterMap)).getOrThrow(); } - @RequestMapping(path = "/names", method = RequestMethod.GET) + // ****************** + // * GET (names) + // ****************** + + @RequestMapping( + path = "/names", + method = RequestMethod.GET, + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) public Collection getNames( @RequestParam( name = Entity.FILTER_ATTR_INSTITUTION, required = true, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, - @RequestParam final Map allRequestParams) { + @RequestParam final MultiValueMap allRequestParams) { checkReadPrivilege(institutionId); final FilterMap filterMap = new FilterMap(allRequestParams); - allRequestParams.putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, String.valueOf(institutionId)); + allRequestParams.putIfAbsent( + Entity.FILTER_ATTR_INSTITUTION, + Arrays.asList(String.valueOf(institutionId))); return getAll(filterMap) .getOrThrow() @@ -129,116 +146,34 @@ public abstract class EntityController this.authorizationGrantService.checkGrantOnEntity( entity, PrivilegeType.READ_ONLY)) .getOrThrow(); } + // ****************** + // * GET (list) + // ****************** + @RequestMapping( - method = RequestMethod.POST, + path = "/list", + method = RequestMethod.GET, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public T create( - @RequestParam final Map allRequestParams, - @RequestParam( - name = Entity.FILTER_ATTR_INSTITUTION, - required = true, - defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) { - - this.authorizationGrantService.checkHasAnyPrivilege( - EntityType.INSTITUTION, - PrivilegeType.WRITE); - - allRequestParams.putIfAbsent(Domain.ATTR_INSTITUTION_ID, String.valueOf(institutionId)); - final M modifyData = this.beanValidationService.validateNewBean( - allRequestParams, - modifiedDataType()); - - final M _modifyData = beforeSave(modifyData); - - return this.checkIsNew(modifyData) - .flatMap(entity -> this.entityDAO.save(_modifyData)) - .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.CREATE, entity)) - .flatMap(entity -> notifySave(_modifyData, entity)) - .getOrThrow(); - } - - @RequestMapping( - method = RequestMethod.PUT, - consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public T savePut(@Valid @RequestBody final M modifyData) { - - final M _modifyData = beforeSave(modifyData); - - return this.authorizationGrantService.checkGrantOnEntity(_modifyData, PrivilegeType.MODIFY) - .flatMap(entity -> this.entityDAO.save(_modifyData)) - .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.MODIFY, entity)) - .flatMap(entity -> notifySave(_modifyData, entity)) - .getOrThrow(); - } - - protected M beforeSave(final M modifyData) { - return modifyData; - } - - @RequestMapping( - path = "/{id}", - method = RequestMethod.PATCH, - consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public T savePost( - @PathVariable final String id, - @RequestParam final Map allRequestParams, - @RequestParam( - name = Entity.FILTER_ATTR_INSTITUTION, - required = true, - defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) { - - final T model = this.entityDAO - .byModelId(id) - .flatMap(entity -> this.authorizationGrantService.checkGrantOnEntity( - entity, - PrivilegeType.MODIFY)) - .getOrThrow(); - - allRequestParams.putIfAbsent(Domain.ATTR_INSTITUTION_ID, String.valueOf(institutionId)); - final M modifyData = this.beanValidationService.validateModifiedBean( - model, - allRequestParams, - modifiedDataType()); - - final M _modifyData = beforeSave(modifyData); - - return this.entityDAO.save(_modifyData) - .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.MODIFY, entity)) - .flatMap(entity -> notifySave(_modifyData, entity)) - .getOrThrow(); - } - - @RequestMapping(path = "/{id}", method = RequestMethod.DELETE) - public EntityProcessingReport hardDelete(@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(); - } - - @RequestMapping(path = "/in", method = RequestMethod.GET) public Collection getForIds(@RequestParam(name = "ids", required = true) final String ids) { return Result.tryCatch(() -> { return Arrays.asList(StringUtils.split(ids, Constants.LIST_SEPARATOR_CHAR)) @@ -253,8 +188,110 @@ public abstract class EntityController notifySave(final M modifyData, final T entity) { - return Result.of(entity); + // ****************** + // * POST (create) + // ****************** + + @RequestMapping( + method = RequestMethod.POST, + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + public T create( + @RequestParam final MultiValueMap allRequestParams, + @RequestParam( + name = Domain.ATTR_INSTITUTION_ID, + required = true, + defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) { + + // check write privilege for requested institution and concrete entityType + this.authorizationGrantService.checkPrivilege( + this.entityDAO.entityType(), + PrivilegeType.WRITE, + institutionId); + + allRequestParams.putIfAbsent( + Domain.ATTR_INSTITUTION_ID, + Arrays.asList(String.valueOf(institutionId))); + final M requestModel = this.createNew(new POSTMapper(allRequestParams)); + + return this.beanValidationService.validateBean(requestModel) + .flatMap(this.entityDAO::createNew) + .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.CREATE, entity)) + .flatMap(entity -> this.notifySaved(requestModel, entity)) + .getOrThrow(); + } + + // **************** + // * PUT (save) + // **************** + + @RequestMapping( + path = "/{modelId}", + method = RequestMethod.PUT, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + public T savePut( + @PathVariable final String modelId, + @Valid @RequestBody final M modifyData) { + + return this.beanValidationService.validateBean(modifyData) + .flatMap(m -> this.authorizationGrantService.checkGrantOnEntity(m, PrivilegeType.MODIFY)) + .flatMap(m -> this.entityDAO.save(modelId, m)) + .flatMap(e -> this.userActivityLogDAO.log(ActivityType.MODIFY, e)) + .flatMap(e -> notifySaved(modifyData, e)) + .getOrThrow(); + } + + // ****************** + // * PATCH (save) + // ****************** + + // NOTE: not supported yet because of difficulties on conversion of params-map to json object +// @RequestMapping( +// path = "/{id}", +// method = RequestMethod.PATCH, +// consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, +// produces = MediaType.APPLICATION_JSON_VALUE) +// public T savePost( +// @PathVariable final String id, +// @RequestParam final MultiValueMap allRequestParams, +// @RequestParam( +// name = Entity.FILTER_ATTR_INSTITUTION, +// required = true, +// defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) { +// +// allRequestParams.putIfAbsent( +// Domain.ATTR_INSTITUTION_ID, +// Arrays.asList(String.valueOf(institutionId))); +// final M requestModel = this.toRequestModel(null, allRequestParams); +// +// return this.entityDAO.save(id, requestModel) +// .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.MODIFY, entity)) +// .flatMap(entity -> notifySaved(requestModel, entity)) +// .getOrThrow(); +// } + + // ****************** + // * DELETE (delete) + // ****************** + + @RequestMapping( + path = "/{id}", + method = RequestMethod.DELETE, + produces = MediaType.APPLICATION_JSON_VALUE) + public EntityProcessingReport hardDelete(@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(); } protected void checkReadPrivilege(final Long institutionId) { @@ -272,16 +309,14 @@ public abstract class EntityController notifySaved(final M modifyData, final T entity) { + return Result.of(entity); + } + + protected abstract M createNew(POSTMapper postParams); + protected abstract Class modifiedDataType(); protected abstract SqlTable getSQLTableOfEntity(); - private Result checkIsNew(final M entity) { - if (entity.getModelId() == null) { - return Result.of(entity); - } else { - return Result - .ofError(new IllegalAPIArgumentException("Request model has already an identifier but should not")); - } - } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java index 54f1ec24..80265708 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java @@ -9,25 +9,39 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlTable; import org.springframework.http.MediaType; +import org.springframework.util.MultiValueMap; +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.POSTMapper; +import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; 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.ExamRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService; @@ -38,6 +52,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; +import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService; @WebServiceProfile @@ -47,6 +63,7 @@ public class ExamAdministrationController extends ActivatableEntityController allRequestParams) { + @RequestParam final MultiValueMap allRequestParams) { checkReadPrivilege(institutionId); @@ -139,77 +158,111 @@ public class ExamAdministrationController extends ActivatableEntityController getIndicatorOfExam(@PathVariable final Long examId) { -// // check read-only grant on Exam -// this.examDAO.byPK(examId) -// .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.READ_ONLY)) -// .getOrThrow(); + @RequestMapping(path = "/{examId}/indicator", method = RequestMethod.GET) + public Collection getIndicatorOfExam(@PathVariable final Long examId) { + // check read-only grant on Exam + this.examDAO.byPK(examId) + .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.READ_ONLY)) + .getOrThrow(); + + return this.indicatorDAO.allForExam(examId) + .getOrThrow(); + } + + @RequestMapping(path = "/{examId}/indicator/{indicatorId}", method = RequestMethod.DELETE) + public Collection deleteIndicatorOfExam( + @PathVariable final Long examId, + @PathVariable(required = false) final Long indicatorId) { + + // check write grant on Exam + this.examDAO.byPK(examId) + .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.WRITE)) + .getOrThrow(); + + final Set toDelete = (indicatorId != null) + ? this.indicatorDAO.allForExam(examId) + .getOrThrow() + .stream() + .map(ind -> new EntityKey(String.valueOf(ind.id), EntityType.INDICATOR)) + .collect(Collectors.toSet()) + : Utils.immutableSetOf(new EntityKey(String.valueOf(indicatorId), EntityType.INDICATOR)); + + this.indicatorDAO.delete(toDelete); + + return this.indicatorDAO.allForExam(examId) + .getOrThrow(); + } + + @RequestMapping(path = "/{examId}/indicator", method = RequestMethod.POST) + public Indicator addNewIndicatorToExam( + @PathVariable final Long examId, + @Valid @RequestBody final Indicator indicator) { + + // check write grant on Exam + this.examDAO.byPK(examId) + .flatMap(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.WRITE)) + .getOrThrow(); + + if (indicator.id != null) { + return this.indicatorDAO.byPK(indicator.id) + .getOrThrow(); + } + + return this.indicatorDAO + .createNew(indicator) + .getOrThrow(); + } + + @RequestMapping(path = "/{examId}/indicator/{id}", method = RequestMethod.PUT) + public Indicator putIndicatorForExam( + @PathVariable final String id, + @Valid @RequestBody final Indicator indicator) { + + // check modify grant on Exam + this.examDAO.byPK(indicator.examId) + .flatMap(e -> this.authorizationGrantService.checkGrantOnEntity(e, PrivilegeType.MODIFY)) + .getOrThrow(); + + return this.indicatorDAO + .save(id, indicator) + .getOrThrow(); + } + +// @RequestMapping(path = "/{examId}/indicator/{id}", method = RequestMethod.PATCH) +// public Indicator patchSaveIndicatorForExam( +// @PathVariable final Long examId, +// @Valid @RequestBody final Indicator indicator) { // -// return this.indicatorDAO.allForExam(examId) -// .getOrThrow(); -// } +// // check modify grant on Exam +// this.examDAO.byPK(examId) +// .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.MODIFY)) +// .getOrThrow(); // -// @RequestMapping(path = "/{examId}/indicator/delete/{indicatorId}", method = RequestMethod.DELETE) -// public Collection deleteIndicatorOfExam( -// @PathVariable final Long examId, -// @PathVariable(required = false) final Long indicatorId) { -// -// // check write grant on Exam -// this.examDAO.byPK(examId) -// .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.WRITE)) -// .getOrThrow(); -// -// final Set toDelete = (indicatorId != null) -// ? this.indicatorDAO.allForExam(examId) -// .getOrThrow() -// .stream() -// .map(ind -> new EntityKey(String.valueOf(ind.id), EntityType.INDICATOR)) -// .collect(Collectors.toSet()) -// : Utils.immutableSetOf(new EntityKey(String.valueOf(indicatorId), EntityType.INDICATOR)); -// -// this.indicatorDAO.delete(toDelete); -// -// return this.indicatorDAO.allForExam(examId) -// .getOrThrow(); -// } -// -// @RequestMapping(path = "/{examId}/indicator/new", method = RequestMethod.POST) -// public Indicator addNewIndicatorToExam( -// @PathVariable final Long examId, -// @Valid @RequestBody final Indicator indicator) { -// -// // check write grant on Exam -// this.examDAO.byPK(examId) -// .flatMap(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.WRITE)) -// .getOrThrow(); -// -// if (indicator.id != null) { -// return this.indicatorDAO.byPK(indicator.id) -// .getOrThrow(); -// } -// -// return this.indicatorDAO -// .save(indicator) -// .getOrThrow(); -// } -// -// @RequestMapping(path = "/{examId}/indicator/save", method = RequestMethod.PUT) -// public Indicator saveIndicatorForExam( -// @PathVariable final Long examId, -// @Valid @RequestBody final Indicator indicator) { -// -// // check modify grant on Exam -// this.examDAO.byPK(examId) -// .map(exam -> this.authorizationGrantService.checkGrantOnEntity(exam, PrivilegeType.MODIFY)) -// .getOrThrow(); -// -// return this.indicatorDAO.save(new Indicator( -// indicator.id, -// examId, -// indicator.name, -// indicator.type, -// indicator.defaultColor, -// indicator.thresholds)).getOrThrow(); -// } +// return this.indicatorDAO.save(new Indicator( +// indicator.id, +// examId, +// indicator.name, +// indicator.type, +// indicator.defaultColor, +// indicator.thresholds)).getOrThrow(); +// } + + @Override + protected Exam createNew(final POSTMapper postParams) { + + final Long lmsSetupId = postParams.getLong(LMS_SETUP.ATTR_ID); + final String quizId = postParams.getString(QuizData.QUIZ_ATTR_ID); + + final LmsAPITemplate lmsAPITemplate = this.lmsAPIService + .createLmsAPITemplate(lmsSetupId) + .getOrThrow(); + + final QuizData quiz = lmsAPITemplate.getQuizzes(new HashSet<>(Arrays.asList(quizId))) + .iterator() + .next() + .getOrThrow(); + + return new Exam(null, quiz, postParams); + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java index 82aa417d..70259269 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/InstitutionController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport; @@ -69,4 +70,13 @@ public class InstitutionController extends ActivatableEntityController importExam( -// @RequestParam(name = LMS_SETUP.ATTR_ID, required = true) final Long lmsSetupId, -// @RequestParam(name = QuizData.QUIZ_ATTR_ID, required = true) final String quizId) { -// -// this.authorizationGrantService.checkHasAnyPrivilege( -// EntityType.EXAM, -// PrivilegeType.WRITE); -// -// final LmsAPITemplate lmsAPITemplate = this.lmsAPIService -// .createLmsAPITemplate(lmsSetupId) -// .getOrThrow(); -// -// final Set ids = new HashSet<>(Arrays.asList( -// StringUtils.split(quizId, Constants.LIST_SEPARATOR_CHAR))); -// -// return lmsAPITemplate.getQuizzes(ids) -// .stream() -// .map(result -> result.flatMap(quiz -> this.examDAO.importFromQuizData( -// lmsAPITemplate.lmsSetup().institutionId, -// lmsSetupId, -// quiz))) -// .flatMap(Result::skipOnError) -// .peek(exam -> this.userActivityLogDAO.log(ActivityType.IMPORT, exam)) -// .collect(Collectors.toList()); -// } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 50a40172..448c6fe1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import ch.ethz.seb.sebserver.gbl.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserMod; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -29,7 +30,7 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint; @WebServiceProfile @RestController -@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACCOUNT) +@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACCOUNT) public class UserAccountController extends ActivatableEntityController { private final ApplicationEventPublisher applicationEventPublisher; @@ -71,7 +72,7 @@ public class UserAccountController extends ActivatableEntityController notifySave(final UserMod userData, final UserInfo userInfo) { + protected Result notifySaved(final UserMod userData, final UserInfo userInfo) { // handle password change; revoke access tokens if password has changed if (userData.passwordChangeRequest() && userData.newPasswordMatch()) { this.applicationEventPublisher.publishEvent( @@ -80,4 +81,9 @@ public class UserAccountController extends ActivatableEntityController() { }); @@ -124,7 +124,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { @Test public void createNewInstitution() throws Exception { // create new institution with seb-admin - final Institution institution = new RestAPITestHelper() + Institution institution = new RestAPITestHelper() .withAccessToken(getSebAdminAccess()) .withPath(RestAPI.ENDPOINT_INSTITUTION) .withMethod(HttpMethod.POST) @@ -151,12 +151,11 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { .getAsObject(new TypeReference() { }); - // and predefined id should not be possible + // and name for institution must be unique errorMessage = new RestAPITestHelper() .withAccessToken(getSebAdminAccess()) .withPath(RestAPI.ENDPOINT_INSTITUTION) .withMethod(HttpMethod.POST) - .withAttribute("id", "123") .withAttribute("name", "new institution") .withAttribute("urlSuffix", "new_inst") .withAttribute("active", "false") @@ -166,6 +165,22 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { assertNotNull(errorMessage); assertEquals("1010", errorMessage.messageCode); + + // and predefined id should be ignored + institution = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(RestAPI.ENDPOINT_INSTITUTION) + .withMethod(HttpMethod.POST) + .withAttribute("id", "123") + .withAttribute("name", "newer institution") + .withAttribute("urlSuffix", "new_inst") + .withAttribute("active", "false") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(institution); + assertEquals("newer institution", institution.name); } // @Test diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java index 5a326d94..9060f393 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java @@ -33,6 +33,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.model.APIMessage; import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; @@ -90,6 +91,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { public void getUserInfoWithUUID() throws Exception { final String sebAdminAccessToken = getSebAdminAccess(); String contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + sebAdminAccessToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -108,6 +110,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String adminInstitution2AccessToken = getAdminInstitution2Access(); contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + adminInstitution2AccessToken)) .andExpect(status().isForbidden()) .andReturn().getResponse().getContentAsString(); @@ -124,7 +127,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception { new RestAPITestHelper() .withAccessToken(getAdminInstitution1Access()) - .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2") + .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "?institutionId=2") .withExpectedStatus(HttpStatus.FORBIDDEN) .getAsString(); } @@ -148,7 +151,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = new RestAPITestHelper() .withAccessToken(getAdminInstitution2Access()) .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) - .withAttribute("institution", "2") + .withAttribute("institutionId", "2") .withExpectedStatus(HttpStatus.OK) .getAsObject(new TypeReference>() { }); @@ -165,8 +168,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = new RestAPITestHelper() .withAccessToken(getAdminInstitution2Access()) .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) - .withAttribute("institution", "2") - .withAttribute("active", "true") + .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") + .withAttribute(Entity.FILTER_ATTR_ACTIVE, "true") .withExpectedStatus(HttpStatus.OK) .getAsObject(new TypeReference>() { }); @@ -181,8 +184,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = new RestAPITestHelper() .withAccessToken(getAdminInstitution2Access()) .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) - .withAttribute("institution", "2") - .withAttribute("active", "false") + .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") + .withAttribute(Entity.FILTER_ATTR_ACTIVE, "false") .withExpectedStatus(HttpStatus.OK) .getAsObject(new TypeReference>() { }); @@ -222,7 +225,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String token = getSebAdminAccess(); final Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institution=2") + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -264,7 +267,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { Page userInfos = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT - + "?page_number=1&page_size=3&institution=2") + + "?page_number=1&page_size=3&institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -282,7 +285,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT - + "?page_number=2&page_size=3&institution=2") + + "?page_number=2&page_size=3&institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -301,7 +304,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT - + "?page_number=3&page_size=3&institution=2") + + "?page_number=3&page_size=3&institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -320,7 +323,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { userInfos = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT - + "?page_number=1&page_size=3&sort_order=DESCENDING&institution=2") + + "?page_number=1&page_size=3&sort_order=DESCENDING&institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -363,7 +366,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { public void getAllUserInfoWithOnlyActive() throws Exception { final String token = getSebAdminAccess(); final Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true&institution=2") + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true&institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -395,9 +398,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // expecting one for institution 2 userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false&institution=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -436,13 +440,15 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { @Test public void createUserTest() throws Exception { - final String token = getSebAdminAccess(); final UserInfo createdUser = this.jsonMapper.readValue( this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) .header("Authorization", "Bearer " + token) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param(Domain.USER.ATTR_NAME, "NewTestUser") + .param(Domain.USER.ATTR_USERNAME, "NewTestUser") + .param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag()) + .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) .param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678") .param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678")) .andExpect(status().isOk()) @@ -456,6 +462,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // get newly created user and check equality final UserInfo createdUserGet = this.jsonMapper.readValue( this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -551,6 +558,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String token = getSebAdminAccess(); final UserInfo user = this.jsonMapper.readValue( this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -565,7 +573,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // change userName, email and roles final UserMod modifyUser = new UserMod(new UserInfo( - user.getUuid(), + null, user.getInstitutionId(), user.getName(), "newUser1", @@ -578,7 +586,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); UserInfo modifiedUserResult = this.jsonMapper.readValue( - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + user.getUuid()) .header("Authorization", "Bearer " + token) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(modifyUserJson)) @@ -597,6 +605,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // double check by getting the user by UUID modifiedUserResult = this.jsonMapper.readValue( this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUserResult.uuid) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -610,39 +619,39 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles)); } - @Test - public void modifyUserWithPOSTMethod() throws Exception { - final String token = getSebAdminAccess(); - - final UserInfo modifiedUser = this.jsonMapper.readValue( - this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param("name", "PostModifyTest")) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(modifiedUser); - assertEquals("PostModifyTest", modifiedUser.name); - - // check validation - final Collection errors = this.jsonMapper.readValue( - this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param("name", "P")) - .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(errors); - assertFalse(errors.isEmpty()); - final APIMessage error = errors.iterator().next(); - assertEquals("1200", error.messageCode); - } +// @Test +// public void modifyUserWithPOSTMethod() throws Exception { +// final String token = getSebAdminAccess(); +// +// final UserInfo modifiedUser = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param("name", "PostModifyTest")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(modifiedUser); +// assertEquals("PostModifyTest", modifiedUser.name); +// +// // check validation +// final Collection errors = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param("name", "P")) +// .andExpect(status().isBadRequest()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference>() { +// }); +// +// assertNotNull(errors); +// assertFalse(errors.isEmpty()); +// final APIMessage error = errors.iterator().next(); +// assertEquals("1200", error.messageCode); +// } @Test public void testOwnerModifyPossibleForExamAdmin() throws Exception { @@ -658,7 +667,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final UserMod modifiedUser = new UserMod(examAdmin, null, null); final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) .header("Authorization", "Bearer " + examAdminToken1) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(modifiedUserJson)) @@ -680,21 +689,13 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { .andExpect(status().isForbidden()) .andReturn().getResponse().getContentAsString(); - this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_INSTITUTION_ID, "2") - .param(Domain.USER.ATTR_NAME, "NewTestUser")) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - final UserInfo userInfo = new UserInfo( null, 2L, "NewTestUser", "NewTestUser", "", true, Locale.CANADA, DateTimeZone.UTC, new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); final String newUserJson = this.jsonMapper.writeValueAsString(newUser); - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/NewTestUser") .header("Authorization", "Bearer " + token) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(newUserJson)) @@ -716,23 +717,13 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { .andExpect(status().isForbidden()) .andReturn().getResponse().getContentAsString(); - this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user3") - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_INSTITUTION_ID, "2") - .param(Domain.USER.ATTR_NAME, "NewTestUser") - .param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678") - .param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678")) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - final UserInfo userInfo = new UserInfo( null, 2L, "NewTestUser", "NewTestUser", "", true, Locale.CANADA, DateTimeZone.UTC, new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); final String newUserJson = this.jsonMapper.writeValueAsString(newUser); - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/NewTestUser") .header("Authorization", "Bearer " + token) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(newUserJson)) @@ -749,6 +740,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String sebAdminToken = getSebAdminAccess(); final UserInfo examAdmin1 = this.jsonMapper.readValue( this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -761,7 +753,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { "newPassword"); final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) .header("Authorization", "Bearer " + sebAdminToken) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(modifiedUserJson)) @@ -795,6 +787,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String sebAdminToken = getSebAdminAccess(); final UserInfo examAdmin1 = this.jsonMapper.readValue( this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -809,7 +802,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); List messages = this.jsonMapper.readValue( - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) .header("Authorization", "Bearer " + sebAdminToken) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(modifiedUserJson)) @@ -831,7 +824,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); messages = this.jsonMapper.readValue( - this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) + this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) .header("Authorization", "Bearer " + sebAdminToken) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(modifiedUserJson)) @@ -997,7 +990,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // all active of institution 2 usersPage = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/active?institution=2") + this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/active?institutionId=2") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) @@ -1011,9 +1004,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { // all inactive of institution 2 usersPage = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/inactive?institution=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) + this.mockMvc + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/inactive?institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -1025,14 +1019,16 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { } @Test - public void testGeneralInEndpoint() throws Exception { + public void testGeneralListEndpoint() throws Exception { final String sebAdminToken = getSebAdminAccess(); // for SEB Admin it should be possible to get from different institutions Collection users = this.jsonMapper.readValue( this.mockMvc - .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/in?ids=user1,user2,user6,user7") - .header("Authorization", "Bearer " + sebAdminToken)) + .perform( + get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -1046,8 +1042,10 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { final String instAdminToken = getAdminInstitution2Access(); users = this.jsonMapper.readValue( this.mockMvc - .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/in?ids=user1,user2,user6,user7") - .header("Authorization", "Bearer " + instAdminToken)) + .perform( + get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + instAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -1066,6 +1064,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { Collection names = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + sebAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -1083,6 +1082,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { names = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + instAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -1100,6 +1100,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { names = this.jsonMapper.readValue( this.mockMvc .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names?active=true") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) .header("Authorization", "Bearer " + instAdminToken)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -1113,6 +1114,44 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { + "EntityIdAndName [entityType=USER, id=user7, name=User]]", names.toString()); } +// @Test +// public void createWithRoleAddRoleDeleteRole() throws Exception { +// final String token = getSebAdminAccess(); +// UserInfo createdUser = this.jsonMapper.readValue( +// this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param(Domain.USER.ATTR_NAME, "NewTestUser") +// .param(Domain.USER.ATTR_USERNAME, "NewTestUser") +// .param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag()) +// .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) +// .param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678") +// .param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(createdUser); +// assertEquals("NewTestUser", createdUser.name); +// assertEquals("[]", String.valueOf(createdUser.roles)); +// +// // add two roles +// createdUser = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param(USER_ROLE.REFERENCE_NAME, "EXAM_SUPPORTER", "EXAM_ADMIN")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(createdUser); +// assertEquals("NewTestUser", createdUser.name); +// assertEquals("[]", String.valueOf(createdUser.roles)); +// } + private UserInfo getUserInfo(final String name, final Collection infos) { try { return infos diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java index a7d125cc..774e339f 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java @@ -47,7 +47,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { // for a user in another institution, the institution has to be defined Page logs = this.jsonMapper.readValue( this.mockMvc - .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4&institution=2") + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4&institutionId=2") .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -82,7 +82,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { final String token = getSebAdminAccess(); Page logs = this.jsonMapper.readValue( this.mockMvc.perform( - get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + sec2) + get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -94,7 +94,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { logs = this.jsonMapper.readValue( this.mockMvc - .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institution=2&from=" + .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 + "&to=" + sec4) .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) @@ -107,9 +107,10 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { 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)) + .perform( + get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 + + "&to=" + sec5) + .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -120,9 +121,10 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { 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)) + .perform( + get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 + + "&to=" + sec6) + .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), new TypeReference>() { @@ -165,7 +167,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { this.mockMvc .perform( get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG - + "?institution=2&activity_types=CREATE,MODIFY") + + "?institutionId=2&activity_types=CREATE,MODIFY") .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(), @@ -209,7 +211,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { this.mockMvc .perform( get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG - + "?entity_types=INSTITUTION,EXAM&institution=2") + + "?entity_types=INSTITUTION,EXAM&institutionId=2") .header("Authorization", "Bearer " + token)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(),