SEBSERV-133 deletion of exams

This commit is contained in:
anhefti 2020-07-22 16:04:42 +02:00
parent cc0f15ab62
commit 6255a6bf38
9 changed files with 360 additions and 11 deletions

View file

@ -0,0 +1,240 @@
/*
* 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;
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.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.exam.Exam;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
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.PageService;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardAction;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.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.exam.DeleteExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamDependencies;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component
@GuiProfile
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 ACTION_REPORT =
new LocTextKey("sebserver.exam.delete.action.report");
private final static LocTextKey DELETE_CONFIRM_TITLE =
new LocTextKey("sebserver.exam.delete.confirm.title");
private final PageService pageService;
protected ExamDeletePopup(final PageService pageService) {
this.pageService = pageService;
}
public Function<PageAction, PageAction> deleteWizardFunction(final PageContext pageContext) {
return action -> {
final ModelInputWizard<PageContext> wizard =
new ModelInputWizard<PageContext>(
action.pageContext().getParent().getShell(),
this.pageService.getWidgetFactory())
.setVeryLargeDialogWidth();
final String page1Id = "DELETE_PAGE";
final String page2Id = "REPORT_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 BiFunction<PageContext, Composite, Supplier<PageContext>> composePage2 =
(prefPageContext, content) -> composeReportDialog(content,
(prefPageContext != null) ? prefPageContext : pageContext);
final WizardPage<PageContext> page1 = new WizardPage<>(
page1Id,
true,
composePage1,
new WizardAction<>(ACTION_DELETE, callback),
new WizardAction<>(ACTION_REPORT, page2Id));
final WizardPage<PageContext> page2 = new WizardPage<>(
page2Id,
false,
composePage2,
new WizardAction<>(ACTION_DELETE, callback));
wizard.open(FORM_TITLE, Utils.EMPTY_EXECUTION, page1, page2);
return action;
};
}
private boolean doDelete(
final PageService pageService,
final PageContext pageContext) {
try {
final EntityKey entityKey = pageContext.getEntityKey();
final Exam examToDelete = this.pageService.getRestService().getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.getOrThrow();
final RestCall<EntityProcessingReport>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(DeleteExam.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name());
final EntityProcessingReport report = restCallBuilder.call().getOrThrow();
final PageAction action = this.pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.EXAM_VIEW_LIST)
.create();
this.pageService.firePageEvent(
new ActionEvent(action),
action.pageContext());
final String examName = 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);
pageContext.notifyUnexpectedError(e);
return false;
}
}
private Supplier<PageContext> composeDeleteDialog(
final Composite parent,
final PageContext pageContext) {
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);
return () -> pageContext;
}
private Supplier<PageContext> composeReportDialog(
final Composite parent,
final PageContext pageContext) {
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollCompositeFilled(parent);
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final Label title = this.pageService.getWidgetFactory()
.labelLocalized(grid, CustomVariant.TEXT_H3, FORM_REPORT_INFO);
final GridData gridData = new GridData();
gridData.horizontalIndent = 10;
gridData.verticalIndent = 10;
title.setLayoutData(gridData);
try {
// get dependencies
final EntityKey entityKey = pageContext.getEntityKey();
final RestCall<Set<EntityDependency>>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(GetExamDependencies.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()) +
" (" + dep.self.getModelId() + ")"))
.withColumn(new ColumnDefinition<>(
"FORM_REPORT_LIST_NAME",
FORM_REPORT_LIST_NAME,
dep -> dep.name))
.withColumn(new ColumnDefinition<>(
"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 Exam delete report page: ", e);
pageContext.notifyUnexpectedError(e);
throw e;
}
}
}

View file

@ -168,12 +168,14 @@ public class ExamForm implements TemplateComposer {
private final String downloadFileName; private final String downloadFileName;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
private final RestService restService; private final RestService restService;
private final ExamDeletePopup examDeletePopup;
protected ExamForm( protected ExamForm(
final PageService pageService, final PageService pageService,
final ExamSEBRestrictionSettings examSEBRestrictionSettings, final ExamSEBRestrictionSettings examSEBRestrictionSettings,
final ExamToConfigBindingForm examToConfigBindingForm, final ExamToConfigBindingForm examToConfigBindingForm,
final DownloadService downloadService, final DownloadService downloadService,
final ExamDeletePopup examDeletePopup,
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) { @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
this.pageService = pageService; this.pageService = pageService;
@ -184,6 +186,7 @@ public class ExamForm implements TemplateComposer {
this.downloadFileName = downloadFileName; this.downloadFileName = downloadFileName;
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.restService = this.resourceService.getRestService(); this.restService = this.resourceService.getRestService();
this.examDeletePopup = examDeletePopup;
this.consistencyMessageMapping = new HashMap<>(); this.consistencyMessageMapping = new HashMap<>();
this.consistencyMessageMapping.put( this.consistencyMessageMapping.put(
@ -248,6 +251,7 @@ public class ExamForm implements TemplateComposer {
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean(); final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(exam); final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(exam);
final boolean modifyGrant = userGrantCheck.m(); final boolean modifyGrant = userGrantCheck.m();
final boolean writeGrant = userGrantCheck.w();
final ExamStatus examStatus = exam.getStatus(); final ExamStatus examStatus = exam.getStatus();
final boolean isExamRunning = examStatus == ExamStatus.RUNNING; final boolean isExamRunning = examStatus == ExamStatus.RUNNING;
final boolean editable = examStatus == ExamStatus.UP_COMING final boolean editable = examStatus == ExamStatus.UP_COMING
@ -396,6 +400,11 @@ public class ExamForm implements TemplateComposer {
.withExec(this.cancelModifyFunction()) .withExec(this.cancelModifyFunction())
.publishIf(() -> !readonly) .publishIf(() -> !readonly)
.newAction(ActionDefinition.EXAM_DELETE)
.withEntityKey(entityKey)
.withExec(this.examDeletePopup.deleteWizardFunction(pageContext))
.publishIf(() -> writeGrant && readonly)
.newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS) .newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService)) .withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService))

View file

@ -51,7 +51,7 @@ 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.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeleteUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeleteUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserDependency; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserDependencies;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@ -273,7 +273,7 @@ public class UserAccountDeletePopup {
// get dependencies // get dependencies
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final RestCall<Set<EntityDependency>>.RestCallBuilder restCallBuilder = this.pageService.getRestService() final RestCall<Set<EntityDependency>>.RestCallBuilder restCallBuilder = this.pageService.getRestService()
.getBuilder(GetUserDependency.class) .getBuilder(GetUserDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .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())
.withQueryParam(API.PARAM_BULK_ACTION_ADD_INCLUDES, Constants.TRUE_STRING); .withQueryParam(API.PARAM_BULK_ACTION_ADD_INCLUDES, Constants.TRUE_STRING);

View file

@ -276,6 +276,11 @@ public enum ActionDefinition {
ImageIcon.TOGGLE_ON, ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.EXAM_VIEW, PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM), ActionCategory.FORM),
EXAM_DELETE(
new LocTextKey("sebserver.exam.action.delete"),
ImageIcon.DELETE,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_MODIFY_SEB_RESTRICTION_DETAILS( EXAM_MODIFY_SEB_RESTRICTION_DETAILS(
new LocTextKey("sebserver.exam.action.sebrestriction.details"), new LocTextKey("sebserver.exam.action.sebrestriction.details"),

View file

@ -0,0 +1,40 @@
/*
* 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class DeleteExam extends RestCall<EntityProcessingReport> {
public DeleteExam() {
super(new TypeKey<>(
CallType.ACTIVATION_DEACTIVATE,
EntityType.EXAM,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.DELETE,
MediaType.APPLICATION_FORM_URLENCODED,
API.EXAM_ADMINISTRATION_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

View file

@ -26,9 +26,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetUserDependency extends RestCall<Set<EntityDependency>> { public class GetUserDependencies extends RestCall<Set<EntityDependency>> {
public GetUserDependency() { public GetUserDependencies() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_DEPENDENCIES, CallType.GET_DEPENDENCIES,
EntityType.USER, EntityType.USER,

View file

@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -268,11 +269,23 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
final List<Long> ids = extractListOfPKs(all); final List<Long> ids = extractListOfPKs(all);
// get all involved configurations
final List<Long> configIds = this.examConfigurationMapRecordMapper.selectByExample()
.where(ExamConfigurationMapRecordDynamicSqlSupport.id, isIn(ids))
.build()
.execute()
.stream()
.map(rec -> rec.getConfigurationNodeId())
.collect(Collectors.toList());
this.examConfigurationMapRecordMapper.deleteByExample() this.examConfigurationMapRecordMapper.deleteByExample()
.where(ExamConfigurationMapRecordDynamicSqlSupport.id, isIn(ids)) .where(ExamConfigurationMapRecordDynamicSqlSupport.id, isIn(ids))
.build() .build()
.execute(); .execute();
updateConfigurationStates(configIds)
.onError(error -> log.error("Unexpected error while update exam configuration state: ", error));
return ids.stream() return ids.stream()
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -534,4 +547,34 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
return (encrypted_encrypt_secret != null) ? encrypted_encrypt_secret.toString() : null; return (encrypted_encrypt_secret != null) ? encrypted_encrypt_secret.toString() : null;
} }
private Result<Set<Long>> updateConfigurationStates(final Collection<Long> configIds) {
return Result.tryCatch(() -> {
return configIds
.stream()
.map(id -> {
final long assignments = this.examConfigurationMapRecordMapper.countByExample()
.where(ExamConfigurationMapRecordDynamicSqlSupport.configurationNodeId, isEqualTo(id))
.build()
.execute();
if (assignments <= 0) {
final ConfigurationNodeRecord newRecord = new ConfigurationNodeRecord(
id,
null,
null,
null,
null,
null,
null,
ConfigurationStatus.READY_TO_USE.name());
this.configurationNodeRecordMapper.updateByPrimaryKeySelective(newRecord);
return id;
} else {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toSet());
});
}
} }

View file

@ -257,7 +257,6 @@ sebserver.useraccount.form.password.new.confirm=Confirm New Password
sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password
sebserver.useraccount.delete.form.title=Delete User Account sebserver.useraccount.delete.form.title=Delete User Account
sebserver.useraccount.delete.form.info.title=Please Note
sebserver.useraccount.delete.form.info=Please Note:<br/>&nbsp;&nbsp;&nbsp;&nbsp;This deletes the particular User Account with all selected dependencies.<br/>&nbsp;&nbsp;&nbsp;&nbsp;The User Account and selected dependent exams and exam configurations, will be lost after deletion.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Please use the "Show Report" action below to see a report of all objects that will be<br/>&nbsp;&nbsp;&nbsp;&nbsp;deleted and check them carefully. sebserver.useraccount.delete.form.info=Please Note:<br/>&nbsp;&nbsp;&nbsp;&nbsp;This deletes the particular User Account with all selected dependencies.<br/>&nbsp;&nbsp;&nbsp;&nbsp;The User Account and selected dependent exams and exam configurations, will be lost after deletion.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Please use the "Show Report" action below to see a report of all objects that will be<br/>&nbsp;&nbsp;&nbsp;&nbsp;deleted and check them carefully.
sebserver.useraccount.delete.form.report.info=The following objects will be deleted within this User Account deletion.<br/>Please check them carefully before delete. sebserver.useraccount.delete.form.report.info=The following objects will be deleted within this User Account deletion.<br/>Please check them carefully before delete.
sebserver.useraccount.delete.form.report.empty=No dependencies will be deleted. sebserver.useraccount.delete.form.report.empty=No dependencies will be deleted.
@ -439,6 +438,7 @@ sebserver.exam.action.import=Import From Quizzes
sebserver.exam.action.save=Save Exam sebserver.exam.action.save=Save Exam
sebserver.exam.action.activate=Activate Exam sebserver.exam.action.activate=Activate Exam
sebserver.exam.action.deactivate=Deactivate Exam sebserver.exam.action.deactivate=Deactivate Exam
sebserver.exam.action.delete=Delete Exam
sebserver.exam.action.sebrestriction.enable=Apply SEB Lock sebserver.exam.action.sebrestriction.enable=Apply SEB Lock
sebserver.exam.action.sebrestriction.disable=Release SEB Lock sebserver.exam.action.sebrestriction.disable=Release SEB Lock
sebserver.exam.action.sebrestriction.details=SEB Restriction Details sebserver.exam.action.sebrestriction.details=SEB Restriction Details
@ -609,6 +609,18 @@ sebserver.exam.indicator.thresholds.list.color.tooltip=The color that is display
sebserver.exam.indicator.thresholds.list.add=Add a new threshold sebserver.exam.indicator.thresholds.list.add=Add a new threshold
sebserver.exam.indicator.thresholds.list.remove=Delete this threshold sebserver.exam.indicator.thresholds.list.remove=Delete this threshold
sebserver.exam.delete.form.title=Delete Exam
sebserver.exam.delete.form.info=Please Note:<br/>&nbsp;&nbsp;&nbsp;&nbsp;This deletes the exam and local import of a course or quiz in SEB Server<br/>&nbsp;&nbsp;&nbsp;&nbsp;This will not delete any course or quiz on a Learning Management System (LMS).<br/>&nbsp;&nbsp;&nbsp;&nbsp;Dependencies of the exam like indicators or SEB client connections will also be deleted.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Please use the "Show Report" action below to see a report of all objects that will be<br/>&nbsp;&nbsp;&nbsp;&nbsp;deleted and check them carefully.
sebserver.exam.delete.report.info=The following objects will be deleted within this exam deletion.<br/>Please check them carefully before delete.
sebserver.exam.delete.report.list.type=Type
sebserver.exam.delete.report.list.name=Name
sebserver.exam.delete.report.list.description=Description
sebserver.exam.delete.action.delete=Delete Exam
sebserver.exam.delete.action.report=Show Report
sebserver.exam.delete.confirm.title==Deletion Successful
sebserver.exam.delete.confirm.message=The Exam ({0}) was successfully deleted.<br/>Also the following number dependencies where successfully deleted: {1}.<br/><br/>And there where {2} errors.
sebserver.exam.delete.report.list.empty=No dependencies will be deleted.
################################ ################################
# Client configuration # Client configuration
################################ ################################

View file

@ -173,7 +173,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.Chang
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeleteUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeleteUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserDependency; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserDependencies;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
@ -2205,7 +2205,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
"examAdmin2", "examAdmin2",
"examAdmin2", "examAdmin2",
new GetUserAccountNames(), new GetUserAccountNames(),
new GetUserDependency(), new GetUserDependencies(),
new GetExam(), new GetExam(),
new GetExamConfigNode()); new GetExamConfigNode());
@ -2217,7 +2217,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.findFirst() .findFirst()
.get(); .get();
List<EntityDependency> dependencies = restService.getBuilder(GetUserDependency.class) List<EntityDependency> dependencies = restService.getBuilder(GetUserDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId())
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
.call() .call()
@ -2265,7 +2265,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
}); });
// only with exam dependencies // only with exam dependencies
dependencies = restService.getBuilder(GetUserDependency.class) dependencies = restService.getBuilder(GetUserDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId())
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
.withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.EXAM.name()) .withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.EXAM.name())
@ -2287,7 +2287,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
// only with configuration dependencies // only with configuration dependencies
dependencies = restService.getBuilder(GetUserDependency.class) dependencies = restService.getBuilder(GetUserDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId())
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
.withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.CONFIGURATION_NODE.name()) .withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.CONFIGURATION_NODE.name())
@ -2305,7 +2305,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
// only with exam and configuration dependencies // only with exam and configuration dependencies
dependencies = restService.getBuilder(GetUserDependency.class) dependencies = restService.getBuilder(GetUserDependencies.class)
.withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId())
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
.withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.CONFIGURATION_NODE.name()) .withQueryParam(API.PARAM_BULK_ACTION_INCLUDES, EntityType.CONFIGURATION_NODE.name())