SEBSERV-133 impl LMS Setup and Institution

This commit is contained in:
anhefti 2022-05-03 17:28:08 +02:00
parent 060e68bb7b
commit 938dafc0dd
21 changed files with 836 additions and 70 deletions

View file

@ -8,7 +8,11 @@
package ch.ethz.seb.sebserver.gbl;
import java.text.Collator;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.RGBA;
@ -19,6 +23,7 @@ import org.springframework.core.ParameterizedTypeReference;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
/** Global Constants used in SEB Server web-service as well as in web-gui component */
@ -155,6 +160,23 @@ public final class Constants {
public static final RGB BLACK_RGB = new RGB(0, 0, 0);
public static final RGBA GREY_DISABLED = new RGBA(150, 150, 150, 50);
public static final Collator DEFAULT_ENGLISH_COLLATOR = Collator.getInstance(Locale.ENGLISH);
public static final List<EntityType> ENTITY_TYPE_HIRARCHIE = Arrays.asList(
EntityType.INSTITUTION,
EntityType.USER,
EntityType.USER_ACTIVITY_LOG,
EntityType.CERTIFICATE,
EntityType.LMS_SETUP,
EntityType.SEB_CLIENT_CONFIGURATION,
EntityType.EXAM_TEMPLATE,
EntityType.EXAM,
EntityType.INDICATOR,
EntityType.EXAM_CONFIGURATION_MAP,
EntityType.CONFIGURATION_NODE,
EntityType.CLIENT_CONNECTION,
EntityType.CLIENT_EVENT);
public static final String IMPORTED_PASSWORD_MARKER = "_IMPORTED_PASSWORD";
public static final TypeReference<Collection<APIMessage>> TYPE_REFERENCE_API_MESSAGE =

View file

@ -11,6 +11,8 @@ package ch.ethz.seb.sebserver.gbl.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.Constants;
@JsonIgnoreProperties(ignoreUnknown = true)
public class EntityDependency implements Comparable<EntityDependency>, ModelIdAware {
@ -113,9 +115,16 @@ public class EntityDependency implements Comparable<EntityDependency>, ModelIdAw
return -1;
}
final int compareTo = this.self.entityType.name().compareTo(other.self.entityType.name());
final int compareTo = Integer.compare(
Constants.ENTITY_TYPE_HIRARCHIE.indexOf(this.self.entityType),
Constants.ENTITY_TYPE_HIRARCHIE.indexOf(other.self.entityType));
//this.self.entityType.name().compareTo(other.self.entityType.name());
if (compareTo == 0) {
return this.self.modelId.compareTo(other.self.modelId);
if (this.name != null) {
return this.name.compareTo(other.name);
} else {
return this.self.modelId.compareTo(other.self.modelId);
}
} else {
return compareTo;
}

View file

@ -16,6 +16,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.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
/** An EntityKey uniquely identifies a domain entity within the SEB Server's domain model.
@ -128,7 +129,11 @@ public class EntityKey implements ModelIdAware, Serializable, Comparable<EntityK
return -1;
}
final int compareTo = this.entityType.name().compareTo(other.entityType.name());
final int compareTo = Constants.DEFAULT_ENGLISH_COLLATOR.compare(
this.entityType.name(),
other.entityType.name());
//this.entityType.name().compareTo(other.entityType.name());
if (compareTo == 0) {
return this.modelId.compareTo(other.modelId);
} else {

View file

@ -73,6 +73,11 @@ public enum ActionDefinition {
ImageIcon.SWITCH,
PageStateDefinitionImpl.INSTITUTION_LIST,
ActionCategory.INSTITUTION_LIST),
INSTITUTION_DELETE(
new LocTextKey("sebserver.institution.action.delete"),
ImageIcon.DELETE,
PageStateDefinitionImpl.INSTITUTION_VIEW,
ActionCategory.FORM),
USER_ACCOUNT_VIEW_LIST(
new LocTextKey("sebserver.useraccount.action.list"),
@ -215,6 +220,11 @@ public enum ActionDefinition {
ImageIcon.SWITCH,
PageStateDefinitionImpl.LMS_SETUP_LIST,
ActionCategory.LMS_SETUP_LIST),
LMS_SETUP_DELETE(
new LocTextKey("sebserver.lmssetup.action.delete"),
ImageIcon.DELETE,
PageStateDefinitionImpl.LMS_SETUP_VIEW,
ActionCategory.FORM),
QUIZ_DISCOVERY_VIEW_LIST(
new LocTextKey("sebserver.quizdiscovery.action.list"),

View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2020 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.content.admin;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
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.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard.WizardAction;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard.WizardPage;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeleteInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionDependency;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component
@GuiProfile
public class InstitutionDeletePopup {
private static final Logger log = LoggerFactory.getLogger(InstitutionDeletePopup.class);
private final static LocTextKey FORM_TITLE =
new LocTextKey("sebserver.institution.delete.form.title");
private final static LocTextKey FORM_INFO =
new LocTextKey("sebserver.institution.delete.form.info");
private final static LocTextKey FORM_REPORT_INFO =
new LocTextKey("sebserver.institution.delete.report.info");
private final static LocTextKey FORM_REPORT_LIST_TYPE =
new LocTextKey("sebserver.institution.delete.report.list.type");
private final static LocTextKey FORM_REPORT_LIST_NAME =
new LocTextKey("sebserver.institution.delete.report.list.name");
private final static LocTextKey FORM_REPORT_LIST_DESC =
new LocTextKey("sebserver.institution.delete.report.list.description");
private final static LocTextKey FORM_REPORT_NONE =
new LocTextKey("sebserver.institution.delete.report.list.empty");
private final static LocTextKey ACTION_DELETE =
new LocTextKey("sebserver.institution.delete.action.delete");
private final static LocTextKey DELETE_CONFIRM_TITLE =
new LocTextKey("sebserver.institution.delete.confirm.title");
private final static LocTextKey DELETE_ERROR_CONSISTENCY =
new LocTextKey("sebserver.institution.action.delete.consistency.error");
private final PageService pageService;
protected InstitutionDeletePopup(final PageService pageService) {
this.pageService = pageService;
}
public Function<PageAction, PageAction> deleteWizardFunction(final PageContext pageContext) {
return action -> {
final ModalInputWizard<PageContext> wizard =
new ModalInputWizard<PageContext>(
action.pageContext().getParent().getShell(),
this.pageService.getWidgetFactory())
.setVeryLargeDialogWidth();
final String page1Id = "DELETE_PAGE";
final Predicate<PageContext> callback = pc -> doDelete(this.pageService, pc);
final BiFunction<PageContext, Composite, Supplier<PageContext>> composePage1 =
(prefPageContext, content) -> composeDeleteDialog(content,
(prefPageContext != null) ? prefPageContext : pageContext);
final WizardPage<PageContext> page1 = new WizardPage<>(
page1Id,
true,
composePage1,
new WizardAction<>(ACTION_DELETE, callback));
wizard.open(FORM_TITLE, Utils.EMPTY_EXECUTION, page1);
return action;
};
}
private boolean doDelete(
final PageService pageService,
final PageContext pageContext) {
try {
final EntityKey entityKey = pageContext.getEntityKey();
final Institution toDelete = this.pageService
.getRestService()
.getBuilder(GetInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.getOrThrow();
final RestCall<EntityProcessingReport>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(DeleteInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
final Result<EntityProcessingReport> deleteCall = restCallBuilder.call();
if (deleteCall.hasError()) {
final Exception error = deleteCall.getError();
if (error instanceof RestCallError) {
final APIMessage message = ((RestCallError) error)
.getAPIMessages()
.stream()
.findFirst()
.orElse(null);
if (message != null && ErrorMessage.INTEGRITY_VALIDATION.isOf(message)) {
pageContext.publishPageMessage(new PageMessageException(DELETE_ERROR_CONSISTENCY));
return false;
}
}
}
final EntityProcessingReport report = deleteCall.getOrThrow();
final PageAction action = this.pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.INSTITUTION_VIEW_LIST)
.create();
this.pageService.firePageEvent(
new ActionEvent(action),
action.pageContext());
final List<EntityKey> dependencies = report.results.stream()
.filter(key -> !key.equals(entityKey))
.collect(Collectors.toList());
pageContext.publishPageMessage(
DELETE_CONFIRM_TITLE,
new LocTextKey(
"sebserver.institution.delete.confirm.message",
toDelete.toName().name,
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 Institution:", e);
pageContext.notifyUnexpectedError(e);
return false;
}
}
private Supplier<PageContext> composeDeleteDialog(
final Composite parent,
final PageContext pageContext) {
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollComposite(parent);
final Label title = this.pageService.getWidgetFactory()
.labelLocalized(grid, CustomVariant.TEXT_H3, FORM_INFO);
final GridData gridData = new GridData();
gridData.horizontalIndent = 10;
gridData.verticalIndent = 10;
title.setLayoutData(gridData);
final Label titleReport = this.pageService.getWidgetFactory()
.labelLocalized(grid, CustomVariant.TEXT_H3, FORM_REPORT_INFO);
final GridData gridDataReport = new GridData();
gridDataReport.horizontalIndent = 10;
gridDataReport.verticalIndent = 10;
titleReport.setLayoutData(gridDataReport);
try {
// get dependencies
final EntityKey entityKey = pageContext.getEntityKey();
final RestCall<Set<EntityDependency>>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(GetInstitutionDependency.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
final Set<EntityDependency> dependencies = restCallBuilder
.call()
.getOrThrow();
final List<EntityDependency> list = dependencies
.stream()
.sorted()
.collect(Collectors.toList());
this.pageService.<EntityDependency> staticListTableBuilder(list, null)
.withEmptyMessage(FORM_REPORT_NONE)
.withColumn(new ColumnDefinition<>(
"FORM_REPORT_LIST_TYPE",
FORM_REPORT_LIST_TYPE,
dep -> i18nSupport
.getText("sebserver.overall.types.entityType." + dep.self.entityType.name())))
.withColumn(new ColumnDefinition<>(
"FORM_REPORT_LIST_NAME",
FORM_REPORT_LIST_NAME,
dep -> dep.name))
.withColumn(new ColumnDefinition<EntityDependency>(
"FORM_REPORT_LIST_DESC",
FORM_REPORT_LIST_DESC,
dep -> dep.description))
.compose(pageContext.copyOf(grid));
return () -> pageContext;
} catch (final Exception e) {
log.error("Error while trying to compose Institution delete report page: ", e);
pageContext.notifyUnexpectedError(e);
throw e;
}
}
}

View file

@ -56,12 +56,16 @@ public class InstitutionForm implements TemplateComposer {
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
private final InstitutionDeletePopup institutionDeletePopup;
protected InstitutionForm(final PageService pageService) {
protected InstitutionForm(
final PageService pageService,
final InstitutionDeletePopup institutionDeletePopup) {
this.pageService = pageService;
this.restService = pageService.getRestService();
this.currentUser = pageService.getCurrentUser();
this.institutionDeletePopup = institutionDeletePopup;
}
@Override
@ -132,6 +136,11 @@ public class InstitutionForm implements TemplateComposer {
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.INSTITUTION_DELETE)
.withEntityKey(entityKey)
.withExec(this.institutionDeletePopup.deleteWizardFunction(pageContext))
.publishIf(() -> writeGrant && isReadonly)
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
.withEntityKey(entityKey)
.withSimpleRestCall(this.restService, DeactivateInstitution.class)

View file

@ -240,9 +240,9 @@ public class ExamForm implements TemplateComposer {
final BooleanSupplier isNew = () -> importFromQuizData;
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(exam);
final boolean modifyGrant = userGrantCheck.m();
final boolean writeGrant = userGrantCheck.w();
final EntityGrantCheck entityGrantCheck = currentUser.entityGrantCheck(exam);
final boolean modifyGrant = entityGrantCheck.m();
final boolean writeGrant = entityGrantCheck.w();
final ExamStatus examStatus = exam.getStatus();
final boolean editable = modifyGrant &&
(examStatus == ExamStatus.UP_COMING || examStatus == ExamStatus.RUNNING);
@ -471,7 +471,7 @@ public class ExamForm implements TemplateComposer {
this.examFormConfigs.compose(
formContext
.copyOf(content)
.withAttribute(ATTR_READ_GRANT, String.valueOf(userGrantCheck.r()))
.withAttribute(ATTR_READ_GRANT, String.valueOf(entityGrantCheck.r()))
.withAttribute(ATTR_EDITABLE, String.valueOf(editable))
.withAttribute(ATTR_EXAM_STATUS, examStatus.name()));
@ -479,7 +479,7 @@ public class ExamForm implements TemplateComposer {
this.examFormIndicators.compose(
formContext
.copyOf(content)
.withAttribute(ATTR_READ_GRANT, String.valueOf(userGrantCheck.r()))
.withAttribute(ATTR_READ_GRANT, String.valueOf(entityGrantCheck.r()))
.withAttribute(ATTR_EDITABLE, String.valueOf(editable))
.withAttribute(ATTR_EXAM_STATUS, examStatus.name()));
}

View file

@ -46,7 +46,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewExamTempl
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExamTemplate;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -199,7 +198,6 @@ public class ExamTemplateForm implements TemplateComposer {
.map(ProctoringServiceSettings::getEnableProctoring)
.getOr(false);
final GrantCheck userGrant = currentUser.grantCheck(EntityType.EXAM_TEMPLATE);
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(examTemplate);
// propagate content actions to action-pane
this.pageService.pageActionBuilder(formContext.clearEntityKeys())

View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2020 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.content.exam;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
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.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard.WizardAction;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputWizard.WizardPage;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeleteLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetupDependencies;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component
@GuiProfile
public class LmsSetupDeletePopup {
private static final Logger log = LoggerFactory.getLogger(LmsSetupDeletePopup.class);
private final static LocTextKey FORM_TITLE =
new LocTextKey("sebserver.lmssetup.delete.form.title");
private final static LocTextKey FORM_INFO =
new LocTextKey("sebserver.lmssetup.delete.form.info");
private final static LocTextKey FORM_REPORT_INFO =
new LocTextKey("sebserver.lmssetup.delete.report.info");
private final static LocTextKey FORM_REPORT_LIST_TYPE =
new LocTextKey("sebserver.lmssetup.delete.report.list.type");
private final static LocTextKey FORM_REPORT_LIST_NAME =
new LocTextKey("sebserver.lmssetup.delete.report.list.name");
private final static LocTextKey FORM_REPORT_LIST_DESC =
new LocTextKey("sebserver.lmssetup.delete.report.list.description");
private final static LocTextKey FORM_REPORT_NONE =
new LocTextKey("sebserver.lmssetup.delete.report.list.empty");
private final static LocTextKey ACTION_DELETE =
new LocTextKey("sebserver.lmssetup.delete.action.delete");
private final static LocTextKey DELETE_CONFIRM_TITLE =
new LocTextKey("sebserver.lmssetup.delete.confirm.title");
private final static LocTextKey DELETE_ERROR_CONSISTENCY =
new LocTextKey("sebserver.lmssetup.action.delete.consistency.error");
private final PageService pageService;
protected LmsSetupDeletePopup(final PageService pageService) {
this.pageService = pageService;
}
public Function<PageAction, PageAction> deleteWizardFunction(final PageContext pageContext) {
return action -> {
final ModalInputWizard<PageContext> wizard =
new ModalInputWizard<PageContext>(
action.pageContext().getParent().getShell(),
this.pageService.getWidgetFactory())
.setVeryLargeDialogWidth();
final String page1Id = "DELETE_PAGE";
final Predicate<PageContext> callback = pc -> doDelete(this.pageService, pc);
final BiFunction<PageContext, Composite, Supplier<PageContext>> composePage1 =
(prefPageContext, content) -> composeDeleteDialog(content,
(prefPageContext != null) ? prefPageContext : pageContext);
final WizardPage<PageContext> page1 = new WizardPage<>(
page1Id,
true,
composePage1,
new WizardAction<>(ACTION_DELETE, callback));
wizard.open(FORM_TITLE, Utils.EMPTY_EXECUTION, page1);
return action;
};
}
private boolean doDelete(
final PageService pageService,
final PageContext pageContext) {
try {
final EntityKey entityKey = pageContext.getEntityKey();
final LmsSetup toDelete = this.pageService
.getRestService()
.getBuilder(GetLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.getOrThrow();
final RestCall<EntityProcessingReport>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(DeleteLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
final Result<EntityProcessingReport> deleteCall = restCallBuilder.call();
if (deleteCall.hasError()) {
final Exception error = deleteCall.getError();
if (error instanceof RestCallError) {
final APIMessage message = ((RestCallError) error)
.getAPIMessages()
.stream()
.findFirst()
.orElse(null);
if (message != null && ErrorMessage.INTEGRITY_VALIDATION.isOf(message)) {
pageContext.publishPageMessage(new PageMessageException(DELETE_ERROR_CONSISTENCY));
return false;
}
}
}
final EntityProcessingReport report = deleteCall.getOrThrow();
final PageAction action = this.pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.LMS_SETUP_VIEW_LIST)
.create();
this.pageService.firePageEvent(
new ActionEvent(action),
action.pageContext());
final List<EntityKey> dependencies = report.results.stream()
.filter(key -> !key.equals(entityKey))
.collect(Collectors.toList());
pageContext.publishPageMessage(
DELETE_CONFIRM_TITLE,
new LocTextKey(
"sebserver.lmssetup.delete.confirm.message",
toDelete.toName().name,
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 LMS Setup:", e);
pageContext.notifyUnexpectedError(e);
return false;
}
}
private Supplier<PageContext> composeDeleteDialog(
final Composite parent,
final PageContext pageContext) {
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollComposite(parent);
final Label title = this.pageService.getWidgetFactory()
.labelLocalized(grid, CustomVariant.TEXT_H3, FORM_INFO);
final GridData gridData = new GridData();
gridData.horizontalIndent = 10;
gridData.verticalIndent = 10;
title.setLayoutData(gridData);
final Label titleReport = this.pageService.getWidgetFactory()
.labelLocalized(grid, CustomVariant.TEXT_H3, FORM_REPORT_INFO);
final GridData gridDataReport = new GridData();
gridDataReport.horizontalIndent = 10;
gridDataReport.verticalIndent = 10;
titleReport.setLayoutData(gridDataReport);
try {
// get dependencies
final EntityKey entityKey = pageContext.getEntityKey();
final RestCall<Set<EntityDependency>>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(GetLmsSetupDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
final Set<EntityDependency> dependencies = restCallBuilder
.call()
.getOrThrow();
final List<EntityDependency> list = dependencies
.stream()
.sorted()
.collect(Collectors.toList());
this.pageService.<EntityDependency> staticListTableBuilder(list, null)
.withEmptyMessage(FORM_REPORT_NONE)
.withColumn(new ColumnDefinition<>(
"FORM_REPORT_LIST_TYPE",
FORM_REPORT_LIST_TYPE,
dep -> i18nSupport
.getText("sebserver.overall.types.entityType." + dep.self.entityType.name())))
.withColumn(new ColumnDefinition<>(
"FORM_REPORT_LIST_NAME",
FORM_REPORT_LIST_NAME,
dep -> dep.name))
.withColumn(new ColumnDefinition<EntityDependency>(
"FORM_REPORT_LIST_DESC",
FORM_REPORT_LIST_DESC,
dep -> dep.description))
.compose(pageContext.copyOf(grid));
return () -> pageContext;
} catch (final Exception e) {
log.error("Error while trying to compose LMS Setup delete report page: ", e);
pageContext.notifyUnexpectedError(e);
throw e;
}
}
}

View file

@ -105,11 +105,15 @@ public class LmsSetupForm implements TemplateComposer {
private final PageService pageService;
private final ResourceService resourceService;
private final LmsSetupDeletePopup lmsSetupDeletePopup;
protected LmsSetupForm(final PageService pageService) {
protected LmsSetupForm(
final PageService pageService,
final LmsSetupDeletePopup lmsSetupDeletePopup) {
this.pageService = pageService;
this.resourceService = pageService.getResourceService();
this.lmsSetupDeletePopup = lmsSetupDeletePopup;
}
@Override
@ -305,6 +309,11 @@ public class LmsSetupForm implements TemplateComposer {
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && readonly && institutionActive)
.newAction(ActionDefinition.LMS_SETUP_DELETE)
.withEntityKey(entityKey)
.withExec(this.lmsSetupDeletePopup.deleteWizardFunction(pageContext))
.publishIf(() -> writeGrant && readonly)
.newAction(ActionDefinition.LMS_SETUP_TEST)
.withEntityKey(entityKey)
.withExec(action -> LmsSetupForm.testLmsSetup(action, formHandle, restService))

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022 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.institution;
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 DeleteInstitution extends RestCall<EntityProcessingReport> {
public DeleteInstitution() {
super(new TypeKey<>(
CallType.DELETE,
EntityType.EXAM,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.DELETE,
MediaType.APPLICATION_FORM_URLENCODED,
API.INSTITUTION_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022 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.lmssetup;
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 DeleteLmsSetup extends RestCall<EntityProcessingReport> {
public DeleteLmsSetup() {
super(new TypeKey<>(
CallType.DELETE,
EntityType.EXAM,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.DELETE,
MediaType.APPLICATION_FORM_URLENCODED,
API.LMS_SETUP_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

View file

@ -25,7 +25,6 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
/** Defines overall DAO support for bulk-actions like activate, deactivate, delete...
*
@ -71,17 +70,24 @@ public interface BulkActionSupportDAO<T extends Entity> {
.get(error -> handleBulkActionError(error, all))
: Collections.emptyList();
case HARD_DELETE:
return (this instanceof EntityDAO)
? ((EntityDAO<?, ?>) this).delete(all)
.map(BulkActionSupportDAO::transformResult)
.get(error -> handleBulkActionError(error, all))
: Collections.emptyList();
return delete(all)
.map(BulkActionSupportDAO::transformResult)
.get(error -> handleBulkActionError(error, all));
}
// should never happen
throw new UnsupportedOperationException("Unsupported Bulk Action: " + bulkAction);
}
/** Use this to delete all entities defined by a set of EntityKey
* NOTE: the Set of EntityKey may contain EntityKey of other entity types like the concrete type of the DAO
* use extractPKsFromKeys to get a list of concrete primary keys for entities to delete
*
* @param all The Collection of EntityKey to delete
* @return Result referring a collection of all entities that has been deleted or refer to an error if
* happened */
Result<Collection<EntityKey>> delete(Set<EntityKey> all);
/** This creates a collection of Results refer the given entity keys.
*
* @param keys Collection of entity keys to create Results from

View file

@ -255,7 +255,10 @@ public class BulkActionServiceImpl implements BulkActionService {
case INSTITUTION:
return Arrays.asList(
this.supporter.get(EntityType.LMS_SETUP),
this.supporter.get(EntityType.CERTIFICATE),
this.supporter.get(EntityType.BATCH_ACTION),
this.supporter.get(EntityType.USER),
this.supporter.get(EntityType.EXAM_TEMPLATE),
this.supporter.get(EntityType.EXAM),
this.supporter.get(EntityType.INDICATOR),
this.supporter.get(EntityType.SEB_CLIENT_CONFIGURATION),

View file

@ -10,8 +10,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
public interface BatchActionDAO extends EntityDAO<BatchAction, BatchAction> {
public interface BatchActionDAO extends EntityDAO<BatchAction, BatchAction>, BulkActionSupportDAO<BatchAction> {
/** This checks if there is a pending batch action to process next.
* If so this reserves the pending batch action and mark it to be processed

View file

@ -17,9 +17,10 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
/** Concrete EntityDAO interface of Certificate entities */
public interface CertificateDAO {
public interface CertificateDAO extends BulkActionSupportDAO<CertificateInfo> {
Result<Certificate> getCertificate(final Long institutionId, String alias);

View file

@ -180,22 +180,7 @@ public interface EntityDAO<T extends Entity, M extends ModelIdAware> {
* @param keys Collection of EntityKey of various types
* @return Set of id's (PK's) from the given key collection that match the concrete EntityType */
default Set<Long> extractPKsFromKeys(final Collection<EntityKey> keys) {
try {
if (keys == null) {
return Collections.emptySet();
}
final EntityType entityType = entityType();
return keys
.stream()
.filter(key -> key.entityType == entityType)
.map(key -> Long.valueOf(key.modelId))
.collect(Collectors.toSet());
} catch (final Exception e) {
log.error("unexpected error while trying to extract PK's from EntityKey's : ", e);
return Collections.emptySet();
}
return extractPKsFromKeys(keys, entityType());
}
/** Context based utility method to extract a set of id's (PK) from a collection of various EntityKey
@ -211,4 +196,32 @@ public interface EntityDAO<T extends Entity, M extends ModelIdAware> {
return new ArrayList<>(extractPKsFromKeys(keys));
}
/** Context based utility method to extract a set of id's (PK) from a collection of various EntityKey
* This uses the EntityType defined by this instance to filter all EntityKey by the given type and
* convert the matching EntityKey's to id's (PK's)
*
* Use this if you need to transform a Collection of EntityKey into a extracted Set of id's of a specified
* EntityType
*
* @param keys Collection of EntityKey of various types
* @param entityType the entity type of the keys to extract
* @return Set of id's (PK's) from the given key collection that match the concrete EntityType */
static Set<Long> extractPKsFromKeys(final Collection<EntityKey> keys, final EntityType entityType) {
try {
if (keys == null) {
return Collections.emptySet();
}
return keys
.stream()
.filter(key -> key.entityType == entityType)
.map(key -> Long.valueOf(key.modelId))
.collect(Collectors.toSet());
} catch (final Exception e) {
log.error("unexpected error while trying to extract PK's from EntityKey's : ", e);
return Collections.emptySet();
}
}
}

View file

@ -35,6 +35,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
@ -43,6 +44,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.BatchActionRecord
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.BatchActionRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttributeRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.BatchActionRecord;
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.BatchActionDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
@ -322,6 +324,17 @@ public class BatchActionDAOImpl implements BatchActionDAO {
.onError(TransactionHandler::rollback);
}
@Override
@Transactional(readOnly = true)
public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) {
return getDependencies(bulkAction, this::allIdsOfInstitution);
}
return Collections.emptySet();
}
@Override
@Transactional
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
@ -419,4 +432,19 @@ public class BatchActionDAOImpl implements BatchActionDAO {
}
}
private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.batchActionRecordMapper.selectByExample()
.where(BatchActionRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId)))
.build()
.execute()
.stream()
.map(rec -> new EntityDependency(
institutionKey,
new EntityKey(rec.getId(), EntityType.BATCH_ACTION),
rec.getActionType(),
rec.getOwner()))
.collect(Collectors.toList()));
}
}

View file

@ -8,6 +8,9 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
import java.io.ByteArrayInputStream;
import java.security.KeyStoreException;
import java.security.PrivateKey;
@ -21,6 +24,7 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
@ -43,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional;
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.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateType;
@ -54,7 +59,9 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.CertificateRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.CertificateRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.CertificateRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.CertificateDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
@ -76,6 +83,11 @@ public class CertificateDAOImpl implements CertificateDAO {
this.cryptor = cryptor;
}
@Override
public EntityType entityType() {
return EntityType.CERTIFICATE;
}
@Override
@Transactional(readOnly = true)
public Result<Certificate> getCertificate(final Long institutionId, final String alias) {
@ -135,6 +147,17 @@ public class CertificateDAOImpl implements CertificateDAO {
.onError(TransactionHandler::rollback);
}
@Override
@Transactional(readOnly = true)
public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) {
return getDependencies(bulkAction, this::allIdsOfInstitution);
}
return Collections.emptySet();
}
@Override
@Transactional(readOnly = true)
public Result<Collection<String>> getAllIdentityAlias(final Long institutionId) {
@ -177,6 +200,28 @@ public class CertificateDAOImpl implements CertificateDAO {
.collect(Collectors.toList()));
}
@Override
@Transactional
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
return Result.tryCatch(() -> {
final List<Long> ids = new ArrayList<>(EntityDAO.extractPKsFromKeys(all, EntityType.CERTIFICATE));
if (ids.isEmpty()) {
return Collections.emptyList();
}
this.certificateRecordMapper.deleteByExample()
.where(CertificateRecordDynamicSqlSupport.id, isIn(ids))
.build()
.execute();
return ids.stream()
.map(id -> new EntityKey(id, EntityType.CERTIFICATE))
.collect(Collectors.toList());
});
}
@Override
public String extractAlias(final X509Certificate certificate, final String alias) {
if (StringUtils.isNotBlank(alias)) {
@ -415,4 +460,19 @@ public class CertificateDAOImpl implements CertificateDAO {
.flatMap(input -> this.cryptor.loadKeyStore(input));
}
private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.certificateRecordMapper.selectByExample()
.where(CertificateRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId)))
.build()
.execute()
.stream()
.map(rec -> new EntityDependency(
institutionKey,
new EntityKey(rec.getId(), EntityType.CERTIFICATE),
rec.getAliases(),
rec.getAliases()))
.collect(Collectors.toList()));
}
}

View file

@ -196,6 +196,18 @@ sebserver.institution.form.logoImage.tooltip=The Image that is shown as a logo i
sebserver.institution.form.logoImage.unsupportedFileType=The selected file is not supported. Supported are: PNG and JPG
sebserver.institution.action.delete=Delete Institution
sebserver.institution.delete.form.title=Delete Institution
sebserver.institution.delete.form.info=Please Note:<br/>&nbsp;&nbsp;&nbsp;&nbsp;This deletes the institution and all related object like LMS Setup, exams and local import of a course<br/>&nbsp;&nbsp;&nbsp;&nbsp;or quiz in SEB Server that belongs to this institution<br/>&nbsp;&nbsp;&nbsp;&nbsp;This will not delete any course or quiz on a Learning Management System (LMS).
sebserver.institution.delete.report.info=The following dependencies will be deleted within this institution deletion.<br/>Please check them carefully before delete.
sebserver.institution.delete.report.list.type=Type
sebserver.institution.delete.report.list.name=Name
sebserver.institution.delete.report.list.description=Description
sebserver.institution.delete.action.delete=Delete All
sebserver.institution.delete.confirm.title=Deletion Successful
sebserver.institution.delete.confirm.message=The institution ({0}) was successfully deleted.<br/>Also the following number of dependencies where successfully deleted: {1}.<br/><br/>And there where {2} errors.
sebserver.institution.delete.report.list.empty=No dependencies will be deleted.
################################
# User Account
################################
@ -368,6 +380,18 @@ sebserver.lmssetup.form.proxy.password=Proxy Password
sebserver.lmssetup.form.proxy.password.tooltip=Proxy authentication password, needed if the proxy requests authentication
sebserver.lmssetup.form.proxy.auth-credentials.tooltip=The proxy authentication credentials (name and password)<br/>to authenticate the connection within the proxy server
sebserver.lmssetup.action.delete=Delete LMS Setup
sebserver.lmssetup.delete.form.title=Delete LMS Setup
sebserver.lmssetup.delete.form.info=Please Note:<br/>&nbsp;&nbsp;&nbsp;&nbsp;This deletes the LMS Setup and all exams and local import of a<br/>&nbsp;&nbsp;&nbsp;&nbsp; course or quiz in SEB Server that belongs to this LMS Setup<br/>&nbsp;&nbsp;&nbsp;&nbsp;This will not delete any course or quiz on a Learning Management System (LMS).
sebserver.lmssetup.delete.report.info=The following dependencies will be deleted within this LMS Setup deletion.<br/>Please check them carefully before delete.
sebserver.lmssetup.delete.report.list.type=Type
sebserver.lmssetup.delete.report.list.name=Name
sebserver.lmssetup.delete.report.list.description=Description
sebserver.lmssetup.delete.action.delete=Delete All
sebserver.lmssetup.delete.confirm.title=Deletion Successful
sebserver.lmssetup.delete.confirm.message=The LMS Setup ({0}) was successfully deleted.<br/>Also the following number of dependencies where successfully deleted: {1}.<br/><br/>And there where {2} errors.
sebserver.lmssetup.delete.report.list.empty=No dependencies will be deleted.
################################
#LMS Exam
################################

View file

@ -2384,18 +2384,18 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.collect(Collectors.toList());
assertEquals(
"[CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "EXAM, "
+ "EXAM_CONFIGURATION_MAP, "
"[EXAM, "
+ "INDICATOR, "
+ "INDICATOR]",
+ "INDICATOR, "
+ "EXAM_CONFIGURATION_MAP, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION]",
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
// check that the user is owner of all depending exams and configurations
@ -2433,14 +2433,14 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.collect(Collectors.toList());
assertEquals(
"[CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "EXAM, "
+ "EXAM_CONFIGURATION_MAP, "
"[EXAM, "
+ "INDICATOR, "
+ "INDICATOR]",
+ "INDICATOR, "
+ "EXAM_CONFIGURATION_MAP, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION]",
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
// only with configuration dependencies
@ -2455,11 +2455,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.collect(Collectors.toList());
assertEquals(
"[CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "EXAM_CONFIGURATION_MAP]",
"[EXAM_CONFIGURATION_MAP, CONFIGURATION_NODE, CONFIGURATION_NODE, CONFIGURATION_NODE, CONFIGURATION_NODE]",
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
// only with exam and configuration dependencies
@ -2475,18 +2471,18 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.collect(Collectors.toList());
assertEquals(
"[CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "EXAM, "
+ "EXAM_CONFIGURATION_MAP, "
"[EXAM, "
+ "INDICATOR, "
+ "INDICATOR]",
+ "INDICATOR, "
+ "EXAM_CONFIGURATION_MAP, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION, "
+ "CLIENT_CONNECTION]",
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
}