SEBSERV-162 audit logs and deletion
This commit is contained in:
parent
f794ab5e7d
commit
a589fd8ad4
16 changed files with 248 additions and 16 deletions
|
@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
|
@ -31,6 +32,7 @@ public class EntityProcessingReport {
|
|||
public static final String ATTR_SOURCE = "source";
|
||||
public static final String ATTR_RESULTS = "results";
|
||||
public static final String ATTR_ERRORS = "errors";
|
||||
public static final String ATTR_TYPE = "bulkActionType";
|
||||
|
||||
/** A set of entity-keys that are or were processed by a bulk action- or other process with a EntityProcessingReport
|
||||
* result. */
|
||||
|
@ -43,16 +45,20 @@ public class EntityProcessingReport {
|
|||
/** A set of error entries that defines an error if happened. */
|
||||
@JsonProperty(value = ATTR_ERRORS, required = true)
|
||||
public final Set<ErrorEntry> errors;
|
||||
@JsonProperty(value = ATTR_TYPE, required = true)
|
||||
public final BulkActionType bulkActionType;
|
||||
|
||||
@JsonCreator
|
||||
public EntityProcessingReport(
|
||||
@JsonProperty(value = ATTR_SOURCE, required = true) final Collection<EntityKey> source,
|
||||
@JsonProperty(value = ATTR_RESULTS, required = true) final Collection<EntityKey> results,
|
||||
@JsonProperty(value = ATTR_ERRORS, required = true) final Collection<ErrorEntry> errors) {
|
||||
@JsonProperty(value = ATTR_ERRORS, required = true) final Collection<ErrorEntry> errors,
|
||||
@JsonProperty(value = ATTR_TYPE, required = true) final BulkActionType bulkActionType) {
|
||||
|
||||
this.source = Utils.immutableSetOf(source);
|
||||
this.results = Utils.immutableSetOf(results);
|
||||
this.errors = Utils.immutableSetOf(errors);
|
||||
this.bulkActionType = bulkActionType;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
|
@ -119,7 +125,8 @@ public class EntityProcessingReport {
|
|||
return new EntityProcessingReport(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.RESOURCE_NOT_FOUND.of())));
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.RESOURCE_NOT_FOUND.of())),
|
||||
null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,6 +138,31 @@ public class IndicatorTemplate implements Entity {
|
|||
return this.thresholds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final IndicatorTemplate other = (IndicatorTemplate) obj;
|
||||
if (this.id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!this.id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
|
|
@ -412,6 +412,11 @@ public enum ActionDefinition {
|
|||
ImageIcon.CANCEL,
|
||||
PageStateDefinitionImpl.EXAM_TEMPLATE_VIEW,
|
||||
ActionCategory.FORM),
|
||||
EXAM_TEMPLATE_DELETE(
|
||||
new LocTextKey("sebserver.examtemplate.form.action.delete"),
|
||||
ImageIcon.DELETE,
|
||||
PageStateDefinitionImpl.EXAM_TEMPLATE_LIST,
|
||||
ActionCategory.FORM),
|
||||
|
||||
INDICATOR_TEMPLATE_NEW(
|
||||
new LocTextKey("sebserver.examtemplate.indicator.action.list.new"),
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -36,6 +38,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteExamTemplate;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicatorTemplate;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamTemplate;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorTemplatePage;
|
||||
|
@ -52,6 +55,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class ExamTemplateForm implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ExamTemplateForm.class);
|
||||
|
||||
public static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examtemplate.form.title");
|
||||
public static final LocTextKey TITLE_NEW_TEXT_KEY =
|
||||
|
@ -85,6 +90,9 @@ public class ExamTemplateForm implements TemplateComposer {
|
|||
private static final LocTextKey INDICATOR_EMPTY_LIST_MESSAGE =
|
||||
new LocTextKey("sebserver.examtemplate.indicator.list.empty");
|
||||
|
||||
private static final LocTextKey EXAM_TEMPLATE_DELETE_CONFIRM =
|
||||
new LocTextKey("sebserver.examtemplate.form.action.delete.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
@ -200,6 +208,12 @@ public class ExamTemplateForm implements TemplateComposer {
|
|||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !readonly)
|
||||
|
||||
.newAction(ActionDefinition.EXAM_TEMPLATE_DELETE)
|
||||
.withEntityKey(entityKey)
|
||||
.withConfirm(() -> EXAM_TEMPLATE_DELETE_CONFIRM)
|
||||
.withExec(this::deleteExamTemplate)
|
||||
.publishIf(() -> userGrant.iw() && readonly)
|
||||
|
||||
;
|
||||
|
||||
if (readonly) {
|
||||
|
@ -277,6 +291,14 @@ public class ExamTemplateForm implements TemplateComposer {
|
|||
}
|
||||
}
|
||||
|
||||
private PageAction deleteExamTemplate(final PageAction action) {
|
||||
this.pageService.getRestService().getBuilder(DeleteExamTemplate.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId)
|
||||
.call()
|
||||
.onError(error -> action.pageContext().notifyUnexpectedError(error));
|
||||
return action;
|
||||
}
|
||||
|
||||
private PageAction deleteSelectedIndicator(final PageAction action) {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
final EntityKey indicatorKey = action.getSingleSelection();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.gui.service.remote.webservice.api.exam;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class DeleteExamTemplate extends RestCall<EntityProcessingReport> {
|
||||
|
||||
public DeleteExamTemplate() {
|
||||
super(new TypeKey<>(
|
||||
CallType.DELETE,
|
||||
EntityType.EXAM_TEMPLATE,
|
||||
new TypeReference<EntityProcessingReport>() {
|
||||
}),
|
||||
HttpMethod.DELETE,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.EXAM_TEMPLATE_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -153,7 +153,8 @@ public class BulkActionServiceImpl implements BulkActionService {
|
|||
action.result.stream()
|
||||
.filter(Result::hasError)
|
||||
.map(this::createErrorEntry)
|
||||
.collect(Collectors.toList()));
|
||||
.collect(Collectors.toList()),
|
||||
action.type);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
|
||||
|
||||
/** Concrete EntityDAO interface of ExamTemplate entities */
|
||||
public interface ExamTemplateDAO extends EntityDAO<ExamTemplate, ExamTemplate> {
|
||||
public interface ExamTemplateDAO extends EntityDAO<ExamTemplate, ExamTemplate>, BulkActionSupportDAO<ExamTemplate> {
|
||||
|
||||
/** Used to get the ExamTemplate that is set as default for a given institution.
|
||||
*
|
||||
|
|
|
@ -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.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
|
@ -76,6 +77,19 @@ public interface UserActivityLogDAO extends
|
|||
* @return Result of the Entity or referring to an Error if happened */
|
||||
<E extends Entity> Result<E> logModify(E entity);
|
||||
|
||||
/** Create a user activity log entry for the current user of activity type DELETE
|
||||
*
|
||||
* @param entity the Entity
|
||||
* @return Result of the Entity or referring to an Error if happened */
|
||||
<E extends Entity> Result<E> logDelete(E entity);
|
||||
|
||||
/** Used to log a successful bulk action and uses the EntityProcessingReport from the
|
||||
* bulk action to log all details.
|
||||
*
|
||||
* @param bulkActionReport the bulk action report containing all processed entity keys for logging
|
||||
* @return Result refer to the given EntityProcessingReport or to an error when happened */
|
||||
Result<EntityProcessingReport> logBulkAction(EntityProcessingReport bulkActionReport);
|
||||
|
||||
/** Creates a user activity log entry for the current user.
|
||||
*
|
||||
* @param activityType the activity type
|
||||
|
|
|
@ -32,6 +32,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
|
|||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
|
||||
|
@ -42,6 +43,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamTemplateRecor
|
|||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamTemplateRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.IndicatorRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamTemplateRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
|
@ -232,6 +234,11 @@ public class ExamTemplateDAOImpl implements ExamTemplateDAO {
|
|||
.onError(TransactionHandler::rollback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
|
|
@ -38,6 +38,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
|||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
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;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
|
@ -87,11 +88,13 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<UserInfo> logLogin(final UserInfo user) {
|
||||
return log(UserLogActivityType.LOGIN, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<UserInfo> logLogout(final UserInfo user) {
|
||||
return log(UserLogActivityType.LOGOUT, user);
|
||||
}
|
||||
|
@ -156,6 +159,50 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
return log(UserLogActivityType.MODIFY, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public <E extends Entity> Result<E> logDelete(final E entity) {
|
||||
return log(UserLogActivityType.DELETE, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<EntityProcessingReport> logBulkAction(final EntityProcessingReport bulkActionReport) {
|
||||
|
||||
try {
|
||||
|
||||
UserLogActivityType activityType = null;
|
||||
switch (bulkActionReport.bulkActionType) {
|
||||
case ACTIVATE:
|
||||
activityType = UserLogActivityType.ACTIVATE;
|
||||
break;
|
||||
case DEACTIVATE:
|
||||
activityType = UserLogActivityType.DEACTIVATE;
|
||||
break;
|
||||
case HARD_DELETE:
|
||||
activityType = UserLogActivityType.DELETE;
|
||||
break;
|
||||
}
|
||||
|
||||
final String message = bulkActionReport.results
|
||||
.stream()
|
||||
.map(EntityKey::toString)
|
||||
.collect(Collectors.joining(Constants.LIST_SEPARATOR));
|
||||
final UserLogActivityType _activityType = activityType;
|
||||
bulkActionReport.source.stream()
|
||||
.forEach(entityKey -> log(
|
||||
_activityType,
|
||||
entityKey.entityType,
|
||||
entityKey.modelId,
|
||||
message));
|
||||
|
||||
return Result.of(bulkActionReport);
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to do audit log for bulk action: ", e);
|
||||
return Result.of(bulkActionReport);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public <E extends Entity> Result<E> log(
|
||||
|
@ -200,6 +247,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public <T> Result<T> log(
|
||||
final UserLogActivityType activityType,
|
||||
final EntityType entityType,
|
||||
|
|
|
@ -150,12 +150,14 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
return new EntityProcessingReport(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))));
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))),
|
||||
BulkActionType.HARD_DELETE);
|
||||
} else {
|
||||
return new EntityProcessingReport(
|
||||
sources,
|
||||
delete.get(),
|
||||
Collections.emptyList());
|
||||
Collections.emptyList(),
|
||||
BulkActionType.HARD_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ 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.WebDataBinder;
|
||||
|
@ -62,6 +64,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
|||
* @param <M> The concrete Entity domain-model type used for POST methods (new) */
|
||||
public abstract class EntityController<T extends Entity, M extends Entity> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EntityController.class);
|
||||
|
||||
protected final AuthorizationService authorization;
|
||||
protected final BulkActionService bulkActionService;
|
||||
protected final EntityDAO<T, M> entityDAO;
|
||||
|
@ -341,6 +345,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this::checkWriteAccess)
|
||||
.flatMap(this::validForDelete)
|
||||
.flatMap(this::logDelete)
|
||||
.flatMap(entity -> bulkDelete(entity, convertToEntityType(addIncludes, includes)))
|
||||
.flatMap(this::notifyDeleted)
|
||||
.flatMap(pair -> this.logBulkAction(pair.b))
|
||||
|
@ -371,7 +376,9 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
}
|
||||
|
||||
final EntityType entityType = this.entityDAO.entityType();
|
||||
final Collection<EntityKey> sources = ids.stream()
|
||||
final Collection<EntityKey> sources = ids
|
||||
.stream()
|
||||
.map(this::logDelete)
|
||||
.map(id -> new EntityKey(id, entityType))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -383,6 +390,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
|
||||
return this.bulkActionService
|
||||
.createReport(bulkAction)
|
||||
.flatMap(this::logBulkAction)
|
||||
.flatMap(this::notifyAllDeleted)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
@ -589,12 +597,42 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return this.userActivityLogDAO.logModify(entity);
|
||||
}
|
||||
|
||||
/** Makes a DELETE user activity log for the specified entity.
|
||||
* This may be overwritten if the create user activity log should be skipped.
|
||||
*
|
||||
* @param entity the Entity instance
|
||||
* @return Result refer to the logged Entity instance or to an error if happened */
|
||||
protected String logDelete(final String modelId) {
|
||||
try {
|
||||
return this.entityDAO
|
||||
.byModelId(modelId)
|
||||
.flatMap(this::logDelete)
|
||||
.map(Entity::getModelId)
|
||||
.getOrThrow();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to log delete for entity id: {}", modelId, e);
|
||||
return modelId;
|
||||
}
|
||||
}
|
||||
|
||||
/** Makes a DELETE user activity log for the specified entity.
|
||||
* This may be overwritten if the create user activity log should be skipped.
|
||||
*
|
||||
* @param entity the Entity instance
|
||||
* @return Result refer to the logged Entity instance or to an error if happened */
|
||||
protected Result<T> logDelete(final T entity) {
|
||||
return this.userActivityLogDAO.logDelete(entity);
|
||||
}
|
||||
|
||||
/** Makes user activity log for a bulk action.
|
||||
*
|
||||
* @param bulkActionReport the EntityProcessingReport
|
||||
* @return Result of entity */
|
||||
protected Result<EntityProcessingReport> logBulkAction(final EntityProcessingReport bulkActionReport) {
|
||||
// TODO
|
||||
|
||||
this.userActivityLogDAO.logBulkAction(bulkActionReport)
|
||||
.onError(error -> log.warn("Failed to log audit for bulk action: {}", bulkActionReport, error));
|
||||
|
||||
return Result.of(bulkActionReport);
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,9 @@ public class ExamTemplateController extends EntityController<ExamTemplate, ExamT
|
|||
.save(newExamTemplate)
|
||||
.getOrThrow();
|
||||
|
||||
this.userActivityLogDAO.logCreate(newIndicator)
|
||||
.onError(error -> log.error("Failed to log indicator template creation: {}", newIndicator, error));
|
||||
|
||||
return newIndicator;
|
||||
}
|
||||
|
||||
|
@ -235,6 +238,9 @@ public class ExamTemplateController extends EntityController<ExamTemplate, ExamT
|
|||
.save(newExamTemplate)
|
||||
.getOrThrow();
|
||||
|
||||
this.userActivityLogDAO.logModify(modifyData)
|
||||
.onError(error -> log.error("Failed to log indicator template modification: {}", modifyData, error));
|
||||
|
||||
return modifyData;
|
||||
}
|
||||
|
||||
|
@ -259,10 +265,14 @@ public class ExamTemplateController extends EntityController<ExamTemplate, ExamT
|
|||
.byModelId(parentModelId)
|
||||
.getOrThrow();
|
||||
|
||||
final List<IndicatorTemplate> newIndicators = examTemplate.indicatorTemplates
|
||||
final IndicatorTemplate toDelete = examTemplate.indicatorTemplates
|
||||
.stream()
|
||||
.filter(i -> !modelId.equals(i.getModelId()))
|
||||
.collect(Collectors.toList());
|
||||
.filter(i -> modelId.equals(i.getModelId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
final List<IndicatorTemplate> newIndicators = new ArrayList<>(examTemplate.indicatorTemplates);
|
||||
newIndicators.remove(toDelete);
|
||||
|
||||
final ExamTemplate newExamTemplate = new ExamTemplate(
|
||||
examTemplate.id,
|
||||
|
@ -275,6 +285,9 @@ public class ExamTemplateController extends EntityController<ExamTemplate, ExamT
|
|||
.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);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||
|
@ -104,12 +105,14 @@ public class UserActivityLogController extends ReadonlyEntityController<UserActi
|
|||
return new EntityProcessingReport(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))));
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))),
|
||||
BulkActionType.HARD_DELETE);
|
||||
} else {
|
||||
return new EntityProcessingReport(
|
||||
sources,
|
||||
delete.get(),
|
||||
Collections.emptyList());
|
||||
Collections.emptyList(),
|
||||
BulkActionType.HARD_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@ sebserver.overall.types.entityType.LMS_SETUP=LMS Setup
|
|||
sebserver.overall.types.entityType.USER=User Account
|
||||
sebserver.overall.types.entityType.CLIENT_INSTRUCTION=SEB Client Instruction
|
||||
sebserver.overall.types.entityType.EXAM_SEB_RESTRICTION=SEB Exam Restriction
|
||||
sebserver.overall.types.entityType.CERTIFICATE=Certificate
|
||||
sebserver.overall.types.entityType.EXAM_TEMPLATE=Exam Template
|
||||
|
||||
sebserver.overall.activity.title.serveradmin=SEB Server Administration
|
||||
sebserver.overall.activity.title.sebconfig=Configurations
|
||||
|
@ -1636,8 +1638,10 @@ sebserver.examtemplate.form.examConfigTemplate.tooltip=The linked ecam configura
|
|||
sebserver.examtemplate.form.supporter=Exam Supporter
|
||||
sebserver.examtemplate.form.supporter.tooltip=List of all exam supporter user that will automatically be applied to an exam imported with this template.
|
||||
|
||||
sebserver.examtemplate.form.action.save=Save
|
||||
sebserver.examtemplate.form.action.edit=Edit Template Settings
|
||||
sebserver.examtemplate.form.action.save=Save Exam Template
|
||||
sebserver.examtemplate.form.action.edit=Edit Exam Template
|
||||
sebserver.examtemplate.form.action.delete=Delete Exam Template
|
||||
sebserver.examtemplate.form.action.delete.confirm=Are you sure to delete this exam template?<br/><br/>Please note that a reference from a exam that uses this template will also be deleted but the exam itself is not affected.
|
||||
|
||||
sebserver.examtemplate.indicator.list.actions=
|
||||
sebserver.examtemplate.indicator.list.title=Indicator Templates
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.junit.Test;
|
|||
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
|
@ -298,7 +299,8 @@ public class ModelObjectJSONGenerator {
|
|||
Arrays.asList(new EntityKey(1L, EntityType.EXAM)),
|
||||
Arrays.asList(new EntityKey(1L, EntityType.INDICATOR), new EntityKey(2L, EntityType.INDICATOR)),
|
||||
Arrays.asList(new EntityProcessingReport.ErrorEntry(new EntityKey(2L, EntityType.INDICATOR),
|
||||
APIMessage.ErrorMessage.UNEXPECTED.of())));
|
||||
APIMessage.ErrorMessage.UNEXPECTED.of())),
|
||||
BulkActionType.HARD_DELETE);
|
||||
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
||||
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
||||
|
||||
|
|
Loading…
Reference in a new issue