SEBSERV-462 implement force delete
This commit is contained in:
parent
8484e2f6b5
commit
ea94adf29b
11 changed files with 219 additions and 92 deletions
|
@ -81,6 +81,8 @@ public final class API {
|
|||
public static final String TOGGLE_ACTIVITY_PATH_SEGMENT = "/toggle-activity";
|
||||
public static final String INACTIVE_PATH_SEGMENT = "/inactive";
|
||||
|
||||
public static final String FORCE_PATH_SEGMENT = "/force";
|
||||
|
||||
public static final String DEPENDENCY_PATH_SEGMENT = "/dependency";
|
||||
|
||||
public static final String PASSWORD_PATH_SEGMENT = "/password";
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.function.Predicate;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ForceDeleteExam;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
@ -62,28 +63,19 @@ public class ExamDeletePopup {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(ExamDeletePopup.class);
|
||||
|
||||
private final static LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.exam.delete.form.title");
|
||||
private final static LocTextKey FORM_INFO =
|
||||
new LocTextKey("sebserver.exam.delete.form.info");
|
||||
private final static LocTextKey FORM_REPORT_INFO =
|
||||
new LocTextKey("sebserver.exam.delete.report.info");
|
||||
private final static LocTextKey FORM_REPORT_LIST_TYPE =
|
||||
new LocTextKey("sebserver.exam.delete.report.list.type");
|
||||
private final static LocTextKey FORM_REPORT_LIST_NAME =
|
||||
new LocTextKey("sebserver.exam.delete.report.list.name");
|
||||
private final static LocTextKey FORM_REPORT_LIST_DESC =
|
||||
new LocTextKey("sebserver.exam.delete.report.list.description");
|
||||
private final static LocTextKey FORM_REPORT_NONE =
|
||||
new LocTextKey("sebserver.exam.delete.report.list.empty");
|
||||
|
||||
private final static LocTextKey ACTION_DELETE =
|
||||
new LocTextKey("sebserver.exam.delete.action.delete");
|
||||
|
||||
private final static LocTextKey DELETE_CONFIRM_TITLE =
|
||||
new LocTextKey("sebserver.exam.delete.confirm.title");
|
||||
private final static LocTextKey DELETE_ERROR_CONSISTENCY =
|
||||
new LocTextKey("sebserver.exam.action.delete.consistency.error");
|
||||
private final static LocTextKey FORM_TITLE = new LocTextKey("sebserver.exam.delete.form.title");
|
||||
private final static LocTextKey FORM_INFO = new LocTextKey("sebserver.exam.delete.form.info");
|
||||
private final static LocTextKey FORM_REPORT_INFO = new LocTextKey("sebserver.exam.delete.report.info");
|
||||
private final static LocTextKey FORM_REPORT_LIST_TYPE = new LocTextKey("sebserver.exam.delete.report.list.type");
|
||||
private final static LocTextKey FORM_REPORT_LIST_NAME = new LocTextKey("sebserver.exam.delete.report.list.name");
|
||||
private final static LocTextKey FORM_REPORT_LIST_DESC = new LocTextKey("sebserver.exam.delete.report.list.description");
|
||||
private final static LocTextKey FORM_REPORT_NONE = new LocTextKey("sebserver.exam.delete.report.list.empty");
|
||||
private final static LocTextKey ACTION_DELETE = new LocTextKey("sebserver.exam.delete.action.delete");
|
||||
private final static LocTextKey DELETE_CONFIRM_TITLE = new LocTextKey("sebserver.exam.delete.confirm.title");
|
||||
private final static LocTextKey DELETE_ERROR_CONSISTENCY = new LocTextKey("sebserver.exam.action.delete.consistency.error");
|
||||
private final static LocTextKey FORCE_DELETE_CONFIRM_TITLE = new LocTextKey("sebserver.exam.action.delete.force.confirm.title");
|
||||
private final static LocTextKey FORCE_DELETE_CONFIRM_ACTION = new LocTextKey("sebserver.exam.action.delete.force.confirm.action");
|
||||
private final static LocTextKey FORCE_DELETE_CONFIRM = new LocTextKey("sebserver.exam.action.delete.force.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
|
||||
|
@ -131,12 +123,12 @@ public class ExamDeletePopup {
|
|||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
final RestCall<EntityProcessingReport>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
|
||||
final Result<EntityProcessingReport> deleteCall = this.pageService.getRestService()
|
||||
.getBuilder(DeleteExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
|
||||
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
|
||||
.call();
|
||||
|
||||
final Result<EntityProcessingReport> deleteCall = restCallBuilder.call();
|
||||
if (deleteCall.hasError()) {
|
||||
final Exception error = deleteCall.getError();
|
||||
if (error instanceof RestCallError) {
|
||||
|
@ -146,33 +138,33 @@ public class ExamDeletePopup {
|
|||
.findFirst()
|
||||
.orElse(null);
|
||||
if (message != null && ErrorMessage.INTEGRITY_VALIDATION.isOf(message)) {
|
||||
pageContext.publishPageMessage(new PageMessageException(DELETE_ERROR_CONSISTENCY));
|
||||
return false;
|
||||
pageContext.applyConfirmDialog(
|
||||
FORCE_DELETE_CONFIRM_TITLE,
|
||||
FORCE_DELETE_CONFIRM,
|
||||
FORCE_DELETE_CONFIRM_ACTION,
|
||||
confirm -> {
|
||||
if (confirm) {
|
||||
final Result<EntityProcessingReport> forceDeleteCall = this.pageService.getRestService()
|
||||
.getBuilder(ForceDeleteExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
|
||||
.call();
|
||||
|
||||
if (forceDeleteCall.hasError()) {
|
||||
pageContext.notifyUnexpectedError(forceDeleteCall.getError());
|
||||
} else {
|
||||
showSuccessDialog(pageContext, examToDelete, forceDeleteCall.getOrThrow(), entityKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final EntityProcessingReport report = deleteCall.getOrThrow();
|
||||
showSuccessDialog(pageContext, examToDelete, deleteCall.getOrThrow(), entityKey);
|
||||
|
||||
final PageAction action = this.pageService.pageActionBuilder(pageContext)
|
||||
.newAction(ActionDefinition.EXAM_VIEW_LIST)
|
||||
.create();
|
||||
|
||||
this.pageService.firePageEvent(
|
||||
new ActionEvent(action),
|
||||
action.pageContext());
|
||||
|
||||
final String examName = StringEscapeUtils.escapeXml11(examToDelete.toName().name);
|
||||
final List<EntityKey> dependencies = report.results.stream()
|
||||
.filter(key -> !key.equals(entityKey))
|
||||
.collect(Collectors.toList());
|
||||
pageContext.publishPageMessage(
|
||||
DELETE_CONFIRM_TITLE,
|
||||
new LocTextKey(
|
||||
"sebserver.exam.delete.confirm.message",
|
||||
examName,
|
||||
dependencies.size(),
|
||||
(report.errors.isEmpty()) ? "no" : String.valueOf((report.errors.size()))));
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to delete Exam:", e);
|
||||
|
@ -181,6 +173,34 @@ public class ExamDeletePopup {
|
|||
}
|
||||
}
|
||||
|
||||
private void showSuccessDialog(
|
||||
final PageContext pageContext,
|
||||
final Exam examToDelete,
|
||||
final EntityProcessingReport report,
|
||||
final EntityKey entityKey) {
|
||||
|
||||
final PageAction action = this.pageService.pageActionBuilder(pageContext)
|
||||
.newAction(ActionDefinition.EXAM_VIEW_LIST)
|
||||
.create();
|
||||
|
||||
this.pageService.firePageEvent(
|
||||
new ActionEvent(action),
|
||||
action.pageContext());
|
||||
|
||||
final String examName = StringEscapeUtils.escapeXml11(examToDelete.toName().name);
|
||||
final List<EntityKey> dependencies = report.results.stream()
|
||||
.filter(key -> !key.equals(entityKey))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
pageContext.publishPageMessage(
|
||||
DELETE_CONFIRM_TITLE,
|
||||
new LocTextKey(
|
||||
"sebserver.exam.delete.confirm.message",
|
||||
examName,
|
||||
dependencies.size(),
|
||||
(report.errors.isEmpty()) ? "no" : String.valueOf((report.errors.size()))));
|
||||
}
|
||||
|
||||
private Supplier<PageContext> composeDeleteDialog(
|
||||
final Composite parent,
|
||||
final PageContext pageContext) {
|
||||
|
|
|
@ -200,6 +200,19 @@ public interface PageContext {
|
|||
* @param callback callback code block that will be called on users selection */
|
||||
void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback);
|
||||
|
||||
/** Apply a confirm dialog with a specified confirm message and a callback code
|
||||
* block that will be executed on users OK selection.
|
||||
*
|
||||
* @param confirmTitle the title of the confirm message dialog
|
||||
* @param confirmMessage the localized confirm message key
|
||||
* @param confirmButtonText The text for the confirm button to display
|
||||
* @param callback callback code block that will be called on users selection */
|
||||
void applyConfirmDialog(
|
||||
LocTextKey confirmTitle,
|
||||
LocTextKey confirmMessage,
|
||||
LocTextKey confirmButtonText,
|
||||
Consumer<Boolean> callback);
|
||||
|
||||
/** This can be used to forward to a defined page.
|
||||
*
|
||||
* @param pageDefinition the defined page */
|
||||
|
|
|
@ -64,18 +64,20 @@ public class ComposerServiceImpl implements ComposerService {
|
|||
private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class;
|
||||
|
||||
final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final PageService pageService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final Map<String, TemplateComposer> composer;
|
||||
private final Map<String, PageDefinition> pages;
|
||||
|
||||
public ComposerServiceImpl(
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
final I18nSupport i18nSupport,
|
||||
final PageService pageService,
|
||||
final Collection<TemplateComposer> composer,
|
||||
final Collection<PageDefinition> pageDefinitions) {
|
||||
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.pageService = pageService;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.composer = composer
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
|
@ -233,7 +235,7 @@ public class ComposerServiceImpl implements ComposerService {
|
|||
}
|
||||
|
||||
private PageContext createPageContext(final Composite root) {
|
||||
return new PageContextImpl(this.i18nSupport, this, root, root, null);
|
||||
return new PageContextImpl(this.pageService, this, root, root, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -184,10 +184,8 @@ public final class PageAction {
|
|||
}
|
||||
} catch (final PageMessageException pme) {
|
||||
PageAction.this.pageContext.publishPageMessage(pme);
|
||||
return;
|
||||
} catch (final Exception e) {
|
||||
this.pageContext.notifyUnexpectedError(e);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
callback.accept(exec());
|
||||
|
|
|
@ -14,16 +14,18 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.widgets.DialogCallback;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -35,10 +37,6 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
|
||||
public class PageContextImpl implements PageContext {
|
||||
|
@ -48,6 +46,7 @@ public class PageContextImpl implements PageContext {
|
|||
private static final LocTextKey UNEXPECTED_ERROR = new LocTextKey("sebserver.error.unexpected");
|
||||
private static final String ENTITY_LIST_TYPE = null;
|
||||
|
||||
private final PageService pageService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final ComposerService composerService;
|
||||
private final Composite root;
|
||||
|
@ -55,13 +54,14 @@ public class PageContextImpl implements PageContext {
|
|||
private final Map<String, String> attributes;
|
||||
|
||||
PageContextImpl(
|
||||
final I18nSupport i18nSupport,
|
||||
final PageService pageService,
|
||||
final ComposerService composerService,
|
||||
final Composite root,
|
||||
final Composite parent,
|
||||
final Map<String, String> attributes) {
|
||||
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.pageService = pageService;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.composerService = composerService;
|
||||
this.root = root;
|
||||
this.parent = parent;
|
||||
|
@ -105,7 +105,7 @@ public class PageContextImpl implements PageContext {
|
|||
@Override
|
||||
public PageContext copyOf(final Composite parent) {
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport,
|
||||
this.pageService,
|
||||
this.composerService,
|
||||
this.root,
|
||||
parent,
|
||||
|
@ -118,7 +118,7 @@ public class PageContextImpl implements PageContext {
|
|||
attrs.putAll(this.attributes);
|
||||
attrs.putAll(((PageContextImpl) otherContext).attributes);
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport,
|
||||
this.pageService,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
|
@ -130,7 +130,7 @@ public class PageContextImpl implements PageContext {
|
|||
final Map<String, String> attrs = new HashMap<>(this.attributes);
|
||||
attrs.put(key, value);
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport,
|
||||
this.pageService,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
|
@ -238,7 +238,7 @@ public class PageContextImpl implements PageContext {
|
|||
final Map<String, String> attrs = new HashMap<>(this.attributes);
|
||||
attrs.remove(name);
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport,
|
||||
this.pageService,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
|
@ -248,7 +248,7 @@ public class PageContextImpl implements PageContext {
|
|||
@Override
|
||||
public PageContext clearAttributes() {
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport,
|
||||
this.pageService,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
|
@ -267,6 +267,36 @@ public class PageContextImpl implements PageContext {
|
|||
messageBox.open(new ConfirmDialogCallback(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyConfirmDialog(
|
||||
final LocTextKey confirmTitle,
|
||||
final LocTextKey confirmMessage,
|
||||
final LocTextKey confirmButtonText,
|
||||
final Consumer<Boolean> callback) {
|
||||
|
||||
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
|
||||
this.root.getShell(),
|
||||
this.pageService.getWidgetFactory());
|
||||
dialog.setDialogWidth(500);
|
||||
|
||||
|
||||
final ModalInputDialogComposer<Void> contentComposer = comp -> {
|
||||
this.pageService.getWidgetFactory().labelLocalized(comp, confirmMessage, true);
|
||||
return () -> (Void) null;
|
||||
};
|
||||
final BiConsumer<Composite, Supplier<Void>> actionComposer = (actionsComp, value) -> {
|
||||
final Button confirm = this.pageService.getWidgetFactory()
|
||||
.buttonLocalized(actionsComp, confirmButtonText);
|
||||
|
||||
confirm.addListener(SWT.Selection, event -> {
|
||||
dialog.close();
|
||||
callback.accept(true);
|
||||
});
|
||||
};
|
||||
|
||||
dialog.openWithActions(confirmTitle, actionComposer, () -> callback.accept(false), contentComposer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forwardToPage(final PageDefinition pageDefinition) {
|
||||
this.composerService.compose(
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam;
|
||||
|
||||
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;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ForceDeleteExam extends RestCall<EntityProcessingReport> {
|
||||
|
||||
public ForceDeleteExam() {
|
||||
super(new TypeKey<>(
|
||||
CallType.DELETE,
|
||||
EntityType.EXAM,
|
||||
new TypeReference<EntityProcessingReport>() {
|
||||
}),
|
||||
HttpMethod.DELETE,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.EXAM_ADMINISTRATION_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT + API.FORCE_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -439,7 +439,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
|||
|
||||
if (protectedRun.hasError()) {
|
||||
final Throwable cause = protectedRun.getError().getCause();
|
||||
if (cause.getMessage().contains("LMS Warnings")) {
|
||||
if (cause != null && cause.getMessage().contains("LMS Warnings")) {
|
||||
return Result.ofRuntimeError(cause.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ public class SEBClientEventBatchService {
|
|||
private static final Logger log = LoggerFactory.getLogger(SEBClientEventBatchService.class);
|
||||
|
||||
private final SEBClientNotificationService sebClientNotificationService;
|
||||
private final SqlSessionFactory sqlSessionFactory;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final ExamSessionCacheService examSessionCacheService;
|
||||
private final JSONMapper jsonMapper;
|
||||
|
@ -65,13 +64,12 @@ public class SEBClientEventBatchService {
|
|||
final JSONMapper jsonMapper) {
|
||||
|
||||
this.sebClientNotificationService = sebClientNotificationService;
|
||||
this.sqlSessionFactory = sqlSessionFactory;
|
||||
this.transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
this.examSessionCacheService = examSessionCacheService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
|
||||
this.sqlSessionTemplate = new SqlSessionTemplate(this.sqlSessionFactory, ExecutorType.BATCH);
|
||||
this.sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
|
||||
this.clientEventMapper = this.sqlSessionTemplate.getMapper(ClientEventRecordMapper.class);
|
||||
}
|
||||
|
||||
|
@ -172,7 +170,7 @@ public class SEBClientEventBatchService {
|
|||
|
||||
this.sqlSessionTemplate.flushStatements();
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.debug("SEBClientEventBatchService worker {} processes batch of size {} in {} ms",
|
||||
workerName,
|
||||
size,
|
||||
|
@ -227,7 +225,7 @@ public class SEBClientEventBatchService {
|
|||
eventData.event.eventType,
|
||||
eventData.event.getClientTime(),
|
||||
eventData.event.getServerTime(),
|
||||
(eventData.event.numValue != null) ? eventData.event.numValue.doubleValue() : null,
|
||||
(eventData.event.numValue != null) ? eventData.event.numValue : null,
|
||||
typeAndPlainText.b,
|
||||
typeAndPlainText.a);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.stream.Collectors;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -38,13 +39,6 @@ import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
|||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Pair;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
|
@ -97,8 +91,8 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
|
||||
/** This is called by Spring to initialize the WebDataBinder and is used here to
|
||||
* initialize the default value binding for the institutionId request-parameter
|
||||
* that has the current users insitutionId as default.
|
||||
*
|
||||
* that has the current users institutionId as default.
|
||||
* <p>
|
||||
* See also UserService.addUsersInstitutionDefaultPropertySupport */
|
||||
@InitBinder
|
||||
public void initBinder(final WebDataBinder binder) {
|
||||
|
@ -293,10 +287,10 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
+ "This is the name of the enumeration "),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_ADD_INCLUDES,
|
||||
description = "Indicates if the following 'includes' paramerer shall be processed or not.\n The default is false "),
|
||||
description = "Indicates if the following 'includes' parameter shall be processed or not.\n The default is false "),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_INCLUDES,
|
||||
description = "A comma separated list of names of the EntityType enummeration that defines all entity types that shall be included in the result.")
|
||||
description = "A comma separated list of names of the EntityType enumeration that defines all entity types that shall be included in the result.")
|
||||
})
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT + API.DEPENDENCY_PATH_SEGMENT,
|
||||
|
@ -466,7 +460,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
summary = "Deletes a single entity (and all its dependencies) by its modelId.",
|
||||
description = "To check or report what dependent object also would be deleted for a certain entity object, "
|
||||
+
|
||||
"please use the dependency endpoint to get a report of all dependend entity objects.",
|
||||
"please use the dependency endpoint to get a report of all dependent entity objects.",
|
||||
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
content = { @Content(mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) }),
|
||||
parameters = {
|
||||
|
@ -476,10 +470,10 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
in = ParameterIn.PATH),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_ADD_INCLUDES,
|
||||
description = "Indicates if the following 'includes' paramerer shall be processed or not.\n The default is false "),
|
||||
description = "Indicates if the following 'includes' parameter shall be processed or not.\n The default is false "),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_INCLUDES,
|
||||
description = "A comma separated list of names of the EntityType enummeration that defines all entity types that shall be included in the result.")
|
||||
description = "A comma separated list of names of the EntityType enumeration that defines all entity types that shall be included in the result.")
|
||||
})
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
|
@ -500,6 +494,43 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Force deletes a single entity (and all its dependencies) by its modelId.",
|
||||
description = "To check or report what dependent object also would be deleted for a certain entity object, "
|
||||
+
|
||||
"please use the dependency endpoint to get a report of all dependent entity objects.",
|
||||
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
content = { @Content(mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) }),
|
||||
parameters = {
|
||||
@Parameter(
|
||||
name = API.PARAM_MODEL_ID,
|
||||
description = "The model identifier of the entity object to get.",
|
||||
in = ParameterIn.PATH),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_ADD_INCLUDES,
|
||||
description = "Indicates if the following 'includes' parameter shall be processed or not.\n The default is false "),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_INCLUDES,
|
||||
description = "A comma separated list of names of the EntityType enumeration that defines all entity types that shall be included in the result.")
|
||||
})
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT + API.FORCE_PATH_SEGMENT,
|
||||
method = RequestMethod.DELETE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public EntityProcessingReport forceHardDelete(
|
||||
@PathVariable final String modelId,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_ADD_INCLUDES, defaultValue = "false") final boolean addIncludes,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) {
|
||||
|
||||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this::checkWriteAccess)
|
||||
.flatMap(this::logDelete)
|
||||
.flatMap(entity -> bulkDelete(entity, convertToEntityType(addIncludes, includes)))
|
||||
.flatMap(this::notifyDeleted)
|
||||
.flatMap(pair -> this.logBulkAction(pair.b))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
// **************************
|
||||
// * DELETE ALL (hard-delete)
|
||||
// **************************
|
||||
|
@ -508,7 +539,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
summary = "Deletes all given entity (and all its dependencies) by a given list of model identifiers.",
|
||||
description = "To check or report what dependent object also would be deleted for a certain entity object, "
|
||||
+
|
||||
"please use the dependency endpoint to get a report of all dependend entity objects.",
|
||||
"please use the dependency endpoint to get a report of all dependent entity objects.",
|
||||
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
content = { @Content(mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) }),
|
||||
parameters = {
|
||||
|
@ -521,7 +552,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
description = "Indicates if the following 'includes' paramerer shall be processed or not.\n The default is false "),
|
||||
@Parameter(
|
||||
name = API.PARAM_BULK_ACTION_INCLUDES,
|
||||
description = "A comma separated list of names of the EntityType enummeration that defines all entity types that shall be included in the result.")
|
||||
description = "A comma separated list of names of the EntityType enumeration that defines all entity types that shall be included in the result.")
|
||||
})
|
||||
@RequestMapping(
|
||||
method = RequestMethod.DELETE,
|
||||
|
@ -547,11 +578,11 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
final Collection<EntityKey> sources = ids.stream()
|
||||
.map(id -> {
|
||||
return this.entityDAO.byModelId(id)
|
||||
.flatMap(exam -> this.validForDelete(exam))
|
||||
.flatMap(this::validForDelete)
|
||||
.getOr(null);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.map(exam -> exam.getModelId())
|
||||
.map(ModelIdAware::getModelId)
|
||||
.map(id -> new EntityKey(id, entityType))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -756,9 +787,9 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
}
|
||||
|
||||
/** Get the EntityType of the GrantEntity that is used for grant checks of the concrete Entity.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: override this if the EntityType of the GrantEntity is not the same as the Entity itself.
|
||||
* For example, the Exam is the GrantEntity of a Indicator
|
||||
* For example, the Exam is the GrantEntity of an Indicator
|
||||
*
|
||||
* @return the EntityType of the GrantEntity that is used for grant checks of the concrete Entity */
|
||||
protected EntityType getGrantEntityType() {
|
||||
|
|
|
@ -554,6 +554,9 @@ sebserver.exam.action.activate=Activate Exam
|
|||
sebserver.exam.action.deactivate=Deactivate Exam
|
||||
sebserver.exam.action.delete=Delete Exam
|
||||
sebserver.exam.action.delete.consistency.error=Deletion Failed.<br/>Please make sure there are no active SEB clients connected to the exam before deletion.
|
||||
sebserver.exam.action.delete.force.confirm.title=Deletion Failed due to condition violation
|
||||
sebserver.exam.action.delete.force.confirm.action=Force Delete
|
||||
sebserver.exam.action.delete.force.confirm=There are still some active SEB client connections for this exam.<br/><br/>Please use "Force Delete" to delete anyway or "Cancel" to aboard deletion.
|
||||
sebserver.exam.action.archive=Archive
|
||||
sebserver.exam.action.archive.confirm=An archived exam cannot be rerun and will remain in read-only view.<br/><br/>Are you sure to archive the exam?
|
||||
sebserver.exam.action.sebrestriction.enable=Apply SEB Lock
|
||||
|
|
Loading…
Reference in a new issue