Skip to content

Commit

Permalink
SEBSERV-462 implement force delete
Browse files Browse the repository at this point in the history
  • Loading branch information
anhefti committed Dec 19, 2023
1 parent 8484e2f commit ea94adf
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 92 deletions.
2 changes: 2 additions & 0 deletions src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ private BatchActionType(final EntityType entityType) {
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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -131,12 +123,12 @@ private boolean doDelete(
.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) {
Expand All @@ -146,33 +138,33 @@ private boolean doDelete(
.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();

final PageAction action = this.pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.EXAM_VIEW_LIST)
.create();

this.pageService.firePageEvent(
new ActionEvent(action),
action.pageContext());
showSuccessDialog(pageContext, examToDelete, deleteCall.getOrThrow(), entityKey);

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);
Expand All @@ -181,6 +173,34 @@ private boolean doDelete(
}
}

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ interface AttributeKeys {
* @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 */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -233,7 +235,7 @@ public void loadMainPage(final Composite parent) {
}

private PageContext createPageContext(final Composite root) {
return new PageContextImpl(this.i18nSupport, this, root, root, null);
return new PageContextImpl(this.pageService, this, root, root, null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,8 @@ void applyAction(final Consumer<Result<PageAction>> callback) {
}
} catch (final PageMessageException pme) {
PageAction.this.pageContext.publishPageMessage(pme);
return;
} catch (final Exception e) {
this.pageContext.notifyUnexpectedError(e);
return;
}
} else {
callback.accept(exec());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
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;

Expand All @@ -35,10 +37,6 @@
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 {
Expand All @@ -48,20 +46,22 @@ 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;
private final Composite parent;
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;
Expand Down Expand Up @@ -105,7 +105,7 @@ public PageContext copy() {
@Override
public PageContext copyOf(final Composite parent) {
return new PageContextImpl(
this.i18nSupport,
this.pageService,
this.composerService,
this.root,
parent,
Expand All @@ -118,7 +118,7 @@ public PageContext copyOfAttributes(final PageContext otherContext) {
attrs.putAll(this.attributes);
attrs.putAll(((PageContextImpl) otherContext).attributes);
return new PageContextImpl(
this.i18nSupport,
this.pageService,
this.composerService,
this.root,
this.parent,
Expand All @@ -130,7 +130,7 @@ public PageContext withAttribute(final String key, final String value) {
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,
Expand Down Expand Up @@ -238,7 +238,7 @@ public PageContext removeAttribute(final String name) {
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,
Expand All @@ -248,7 +248,7 @@ public PageContext removeAttribute(final String name) {
@Override
public PageContext clearAttributes() {
return new PageContextImpl(
this.i18nSupport,
this.pageService,
this.composerService,
this.root,
this.parent,
Expand All @@ -267,6 +267,36 @@ public void applyConfirmDialog(final LocTextKey confirmMessage, final Consumer<B
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}
Loading

0 comments on commit ea94adf

Please sign in to comment.