From 9ed1d961836075a42438956c139aea348372d58b Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 13 Apr 2022 10:53:26 +0200 Subject: [PATCH] SEBSERV-292 fixed and also added unique name check for indicators --- .../gbl/model/exam/IndicatorTemplate.java | 13 +- .../servicelayer/dao/ExamTemplateDAO.java | 20 +++ .../servicelayer/dao/UserActivityLogDAO.java | 7 + .../dao/impl/ExamTemplateDAOImpl.java | 163 +++++++++++++++++- .../dao/impl/UserActivityLogDAOImpl.java | 9 + .../weblayer/api/ExamTemplateController.java | 121 ++----------- 6 files changed, 221 insertions(+), 112 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/IndicatorTemplate.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/IndicatorTemplate.java index b9dfec50..a84c7380 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/IndicatorTemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/IndicatorTemplate.java @@ -95,6 +95,17 @@ public class IndicatorTemplate implements Entity { this.thresholds = postParams.getThresholds(); } + public IndicatorTemplate(final Long id, final IndicatorTemplate other) { + this.id = id; + this.examTemplateId = other.examTemplateId; + this.name = other.name; + this.type = other.type; + this.defaultColor = other.defaultColor; + this.defaultIcon = other.defaultIcon; + this.tags = other.tags; + this.thresholds = Utils.immutableListOf(other.thresholds); + } + @Override public String getModelId() { return (this.id == null) ? null : String.valueOf(this.id); @@ -168,7 +179,7 @@ public class IndicatorTemplate implements Entity { final StringBuilder builder = new StringBuilder(); builder.append("Indicator [id="); builder.append(this.id); - builder.append(", examId="); + builder.append(", examTemplateId="); builder.append(this.examTemplateId); builder.append(", name="); builder.append(this.name); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamTemplateDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamTemplateDAO.java index bc57fb24..747c53fc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamTemplateDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamTemplateDAO.java @@ -8,7 +8,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate; +import ch.ethz.seb.sebserver.gbl.model.exam.IndicatorTemplate; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO; @@ -21,4 +23,22 @@ public interface ExamTemplateDAO extends EntityDAO, * @return Result refer to the ExamTemplate instance or to an error when happened */ Result getInstitutionalDefault(Long institutionId); + /** Creates a new indicator template + * + * @param indicatorTemplate The IndicatorTemplate refer also to the exam template (examTemplateId) + * @return Result refer to the created IndicatorTemplate or to an error when happened */ + Result createNewIndicatorTemplate(IndicatorTemplate indicatorTemplate); + + /** Saves an already existing indicator template + * + * @param indicatorTemplate The IndicatorTemplate refer also to the exam template (examTemplateId) + * @return Result refer to the saved IndicatorTemplate or to an error when happened */ + Result saveIndicatorTemplate(IndicatorTemplate indicatorTemplate); + + /** Deletes an already existing indicator template + * + * @param indicatorTemplate The IndicatorTemplate refer also to the exam template (examTemplateId) + * @return Result refer to the EntityKey of the deleted IndicatorTemplate or to an error when happened */ + Result deleteIndicatorTemplate(String examTemplateId, String indicatorTemplateId); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java index 7d432e16..34ece538 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java @@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.user.UserAccount; import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; @@ -83,6 +84,12 @@ public interface UserActivityLogDAO extends * @return Result of the Entity or referring to an Error if happened */ Result logDelete(E entity); + /** Create a user activity log entry for the current user of activity type DELETE + * + * @param entityKey the EntityKey of the deleted object + * @return Result of the EntityKey or referring to an Error if happened */ + Result logDelete(EntityKey entityKey); + /** Used to log a successful bulk action and uses the EntityProcessingReport from the * bulk action to log all details. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamTemplateDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamTemplateDAOImpl.java index 0671d0ac..a5108e47 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamTemplateDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamTemplateDAOImpl.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -220,11 +221,6 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO { checkUniqueName(data); checkUniqueDefault(data); - final Collection indicatorTemplates = data.getIndicatorTemplates(); - final String indicatorsJSON = (indicatorTemplates != null && !indicatorTemplates.isEmpty()) - ? this.jsonMapper.writeValueAsString(indicatorTemplates) - : null; - final ExamTemplateRecord newRecord = new ExamTemplateRecord( data.id, null, @@ -237,7 +233,7 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO { (data.supporter != null) ? StringUtils.join(data.supporter, Constants.LIST_SEPARATOR_CHAR) : null, - indicatorsJSON, + null, BooleanUtils.toInteger(data.institutionalDefault)); this.examTemplateRecordMapper.updateByPrimaryKeySelective(newRecord); @@ -259,6 +255,137 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO { .onError(TransactionHandler::rollback); } + @Override + @Transactional + public Result createNewIndicatorTemplate(final IndicatorTemplate indicatorTemplate) { + return Result.tryCatch(() -> { + + if (log.isDebugEnabled()) { + log.debug("Create new indicator template: {}", indicatorTemplate); + } + + final Long examTemplatePK = indicatorTemplate.examTemplateId; + final ExamTemplateRecord examTemplateRec = this.examTemplateRecordMapper + .selectByPrimaryKey(examTemplatePK); + final String indicatorTemplatesJSON = examTemplateRec.getIndicatorTemplates(); + final Collection indicators = (StringUtils.isNotBlank(indicatorTemplatesJSON)) + ? this.jsonMapper.readValue( + indicatorTemplatesJSON, + new TypeReference>() { + }) + : Collections.emptyList(); + + checkUniqueIndicatorName(indicatorTemplate, indicators); + + final IndicatorTemplate newIndicatorTemplate = new IndicatorTemplate( + getNextIndicatorId(indicators), + indicatorTemplate); + + final List newIndicators = new ArrayList<>(indicators); + newIndicators.add(newIndicatorTemplate); + + final String newIndicatorTemplatesJSON = newIndicators.isEmpty() + ? StringUtils.EMPTY + : this.jsonMapper.writeValueAsString(newIndicators); + + final ExamTemplateRecord newRecord = new ExamTemplateRecord( + examTemplatePK, null, null, null, null, null, null, + newIndicatorTemplatesJSON, null); + + this.examTemplateRecordMapper.updateByPrimaryKeySelective(newRecord); + + return newIndicatorTemplate; + }) + .onError(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result saveIndicatorTemplate(final IndicatorTemplate indicatorTemplate) { + return Result.tryCatch(() -> { + + if (log.isDebugEnabled()) { + log.debug("Save indicator template: {}", indicatorTemplate); + } + + final Long examTemplatePK = indicatorTemplate.examTemplateId; + final ExamTemplateRecord examTemplateRec = this.examTemplateRecordMapper + .selectByPrimaryKey(examTemplatePK); + final String indicatorTemplatesJSON = examTemplateRec.getIndicatorTemplates(); + final Collection indicators = (StringUtils.isNotBlank(indicatorTemplatesJSON)) + ? this.jsonMapper.readValue( + indicatorTemplatesJSON, + new TypeReference>() { + }) + : Collections.emptyList(); + + checkUniqueIndicatorName(indicatorTemplate, indicators); + + final List newIndicators = indicators + .stream() + .map(i -> indicatorTemplate.id.equals(i.id) ? indicatorTemplate : i) + .collect(Collectors.toList()); + + final String newIndicatorTemplatesJSON = newIndicators.isEmpty() + ? StringUtils.EMPTY + : this.jsonMapper.writeValueAsString(newIndicators); + + final ExamTemplateRecord newRecord = new ExamTemplateRecord( + examTemplatePK, null, null, null, null, null, null, + newIndicatorTemplatesJSON, null); + + this.examTemplateRecordMapper.updateByPrimaryKeySelective(newRecord); + + return indicatorTemplate; + }) + .onError(TransactionHandler::rollback); + } + + @Override + @Transactional + public Result deleteIndicatorTemplate( + final String examTemplateId, + final String indicatorTemplateId) { + + return Result.tryCatch(() -> { + + if (log.isDebugEnabled()) { + log.debug( + "Delete indicator template for exam template: {} indicator template id", + examTemplateId, + indicatorTemplateId); + } + + final Long examTemplatePK = Long.valueOf(examTemplateId); + final ExamTemplateRecord examTemplateRec = this.examTemplateRecordMapper + .selectByPrimaryKey(examTemplatePK); + final String indicatorTemplatesJSON = examTemplateRec.getIndicatorTemplates(); + final Collection indicators = (StringUtils.isNotBlank(indicatorTemplatesJSON)) + ? this.jsonMapper.readValue( + indicatorTemplatesJSON, + new TypeReference>() { + }) + : Collections.emptyList(); + + final List newIndicators = indicators.stream() + .filter(indicatorTemplate -> !indicatorTemplateId.equals(indicatorTemplate.getModelId())) + .collect(Collectors.toList()); + + final String newIndicatorTemplatesJSON = newIndicators.isEmpty() + ? StringUtils.EMPTY + : this.jsonMapper.writeValueAsString(newIndicators); + + final ExamTemplateRecord newRecord = new ExamTemplateRecord( + examTemplatePK, null, null, null, null, null, null, + newIndicatorTemplatesJSON, null); + + this.examTemplateRecordMapper.updateByPrimaryKeySelective(newRecord); + + return new EntityKey(indicatorTemplateId, EntityType.INDICATOR); + }) + .onError(TransactionHandler::rollback); + } + @Override public Set getDependencies(final BulkAction bulkAction) { return Collections.emptySet(); @@ -269,7 +396,9 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO { public Result> delete(final Set all) { return Result.tryCatch(() -> { - log.info("Delete exam templates: {}", all); + if (log.isDebugEnabled()) { + log.debug("Delete exam templates: {}", all); + } final List ids = extractListOfPKs(all); if (ids == null || ids.isEmpty()) { @@ -405,4 +534,24 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO { } } + private void checkUniqueIndicatorName(final IndicatorTemplate indicatorTemplate, + final Collection indicators) { + // check unique name + indicators.stream() + .filter(it -> Objects.equals(it.name, indicatorTemplate.name)) + .findAny() + .ifPresent(it -> { + throw new FieldValidationException( + "name", + "indicatorTemplate:name:exists"); + }); + } + + private long getNextIndicatorId(final Collection indicators) { + return indicators.stream() + .map(IndicatorTemplate::getId) + .max(Long::compare) + .orElse(-1L) + 1; + } + } 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 23c6f586..dabfeda0 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 @@ -166,6 +166,15 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { return log(UserLogActivityType.DELETE, entity); } + @Override + @Transactional + public Result logDelete(final EntityKey entityKey) { + return Result.tryCatch(() -> { + log(UserLogActivityType.DELETE, entityKey.entityType, entityKey.modelId, null); + return entityKey; + }); + } + @Override @Transactional public Result logBulkAction(final EntityProcessingReport bulkActionReport) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamTemplateController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamTemplateController.java index dfefafe5..4c223a93 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamTemplateController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamTemplateController.java @@ -8,7 +8,6 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -21,8 +20,6 @@ import javax.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlTable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PathVariable; @@ -48,7 +45,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService; -import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamTemplateDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; @@ -59,12 +55,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe @RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.EXAM_TEMPLATE_ENDPOINT) public class ExamTemplateController extends EntityController { - private static final Logger log = LoggerFactory.getLogger(ExamTemplateController.class); + private final ExamTemplateDAO examTemplateDAO; protected ExamTemplateController( final AuthorizationService authorization, final BulkActionService bulkActionService, - final EntityDAO entityDAO, + final ExamTemplateDAO entityDAO, final UserActivityLogDAO userActivityLogDAO, final PaginationService paginationService, final BeanValidationService beanValidationService) { @@ -76,6 +72,8 @@ public class ExamTemplateController extends EntityController indicators = new ArrayList<>(examTemplate.indicatorTemplates); - indicators.add(newIndicator); - final ExamTemplate newExamTemplate = new ExamTemplate( - examTemplate.id, - null, null, null, null, null, null, - examTemplate.institutionalDefault, - indicators, - null); - - super.entityDAO - .save(newExamTemplate) - .getOrThrow(); - - this.userActivityLogDAO.logCreate(newIndicator) - .onError(error -> log.error("Failed to log indicator template creation: {}", newIndicator, error)); - - return newIndicator; } @RequestMapping( @@ -228,46 +202,11 @@ public class ExamTemplateController extends EntityController newIndicators = examTemplate.indicatorTemplates - .stream() - .map(i -> { - if (modelId.equals(i.getModelId())) { - return new IndicatorTemplate( - modifyData.id, - modifyData.examTemplateId, - modifyData.name, - (modifyData.type != null) ? modifyData.type : i.type, - (modifyData.defaultColor != null) ? modifyData.defaultColor : i.defaultColor, - (modifyData.defaultIcon != null) ? modifyData.defaultIcon : i.defaultIcon, - (modifyData.tags != null) ? modifyData.tags : i.tags, - (modifyData.thresholds != null) ? modifyData.thresholds : i.thresholds); - } else { - return i; - } - }) - .collect(Collectors.toList()); - - final ExamTemplate newExamTemplate = new ExamTemplate( - examTemplate.id, - null, null, null, null, null, null, - examTemplate.institutionalDefault, - newIndicators, - null); - - super.entityDAO - .save(newExamTemplate) - .getOrThrow(); - - this.userActivityLogDAO.logModify(modifyData) - .onError(error -> log.error("Failed to log indicator template modification: {}", modifyData, error)); - - return modifyData; } @RequestMapping( @@ -286,35 +225,9 @@ public class ExamTemplateController extends EntityController modelId.equals(i.getModelId())) - .findFirst() - .orElse(null); - - final List newIndicators = new ArrayList<>(examTemplate.indicatorTemplates); - newIndicators.remove(toDelete); - - final ExamTemplate newExamTemplate = new ExamTemplate( - examTemplate.id, - null, null, null, null, null, null, - examTemplate.institutionalDefault, - newIndicators, - null); - - super.entityDAO - .save(newExamTemplate) - .getOrThrow(); - - this.userActivityLogDAO.logDelete(toDelete) - .onError(error -> log.error("Failed to log indicator template modification: {}", toDelete, error)); - - return new EntityKey(modelId, EntityType.INDICATOR); } @Override