diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityDependency.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityDependency.java new file mode 100644 index 00000000..36fafbdb --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityDependency.java @@ -0,0 +1,114 @@ +/* + * 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.gbl.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class EntityDependency implements Comparable { + + @JsonProperty(value = "parent", required = true) + public final EntityKey parent; + @JsonProperty(value = "self", required = true) + public final EntityKey self; + @JsonProperty(value = "name", required = true) + public final String name; + @JsonProperty(value = "description", required = false) + public final String description; + + public EntityDependency( + @JsonProperty(value = "parent", required = true) final EntityKey parent, + @JsonProperty(value = "self", required = true) final EntityKey self, + @JsonProperty(value = "name", required = true) final String name, + @JsonProperty(value = "description", required = false) final String description) { + + this.parent = parent; + this.self = self; + this.name = name; + this.description = description; + } + + public EntityKey getParent() { + return this.parent; + } + + public EntityKey getSelf() { + return this.self; + } + + public String getName() { + return this.name; + } + + public String getDescription() { + return this.description; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.parent == null) ? 0 : this.parent.hashCode()); + result = prime * result + ((this.self == null) ? 0 : this.self.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final EntityDependency other = (EntityDependency) obj; + if (this.parent == null) { + if (other.parent != null) + return false; + } else if (!this.parent.equals(other.parent)) + return false; + if (this.self == null) { + if (other.self != null) + return false; + } else if (!this.self.equals(other.self)) + return false; + return true; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("EntityDependency [parent="); + builder.append(this.parent); + builder.append(", self="); + builder.append(this.self); + builder.append(", name="); + builder.append(this.name); + builder.append(", description="); + builder.append(this.description); + builder.append("]"); + return builder.toString(); + } + + @Override + public int compareTo(final EntityDependency other) { + if (other == null) { + return -1; + } + + final int compareTo = this.self.entityType.name().compareTo(other.self.entityType.name()); + if (compareTo == 0) { + return this.self.modelId.compareTo(other.self.modelId); + } else { + return compareTo; + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java index 1e3ecc45..f78d5356 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java @@ -78,13 +78,11 @@ public class ConfigTemplateAttributeForm implements TemplateComposer { protected ConfigTemplateAttributeForm( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, final ExamConfigurationService examConfigurationService) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.resourceService = pageService.getResourceService(); this.examConfigurationService = examConfigurationService; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java index 76ebeb9f..cfcda419 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java @@ -80,6 +80,7 @@ public class ConfigTemplateForm implements TemplateComposer { private final PageService pageService; private final RestService restService; private final CurrentUser currentUser; + private final SEBExamConfigCreationPopup sebxamConfigCreationPopup; private final I18nSupport i18nSupport; private final ResourceService resourceService; private final ExamConfigurationService examConfigurationService; @@ -91,16 +92,16 @@ public class ConfigTemplateForm implements TemplateComposer { protected ConfigTemplateForm( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, + final SEBExamConfigCreationPopup sebxamConfigCreationPopup, final ExamConfigurationService examConfigurationService) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.i18nSupport = pageService.getI18nSupport(); this.resourceService = pageService.getResourceService(); this.examConfigurationService = examConfigurationService; + this.sebxamConfigCreationPopup = sebxamConfigCreationPopup; } @@ -292,8 +293,7 @@ public class ConfigTemplateForm implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG) .withEntityKey(entityKey) - .withExec(SEBExamConfigCreationPopup.configCreationFunction( - this.pageService, + .withExec(this.sebxamConfigCreationPopup.configCreationFunction( pageContext .withAttribute( PageContext.AttributeKeys.CREATE_FROM_TEMPLATE, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java index e6c18655..53884ebb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java @@ -72,13 +72,11 @@ public class ConfigTemplateList implements TemplateComposer { protected ConfigTemplateList( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java index c9ab06dd..0a0de89e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java @@ -162,6 +162,8 @@ public class ExamForm implements TemplateComposer { private final PageService pageService; private final ResourceService resourceService; + private final ExamSEBRestrictionSettings examSEBRestrictionSettings; + private final ExamToConfigBindingForm examToConfigBindingForm; private final DownloadService downloadService; private final String downloadFileName; private final WidgetFactory widgetFactory; @@ -169,12 +171,15 @@ public class ExamForm implements TemplateComposer { protected ExamForm( final PageService pageService, - final ResourceService resourceService, + final ExamSEBRestrictionSettings examSEBRestrictionSettings, + final ExamToConfigBindingForm examToConfigBindingForm, final DownloadService downloadService, @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); + this.examSEBRestrictionSettings = examSEBRestrictionSettings; + this.examToConfigBindingForm = examToConfigBindingForm; this.downloadService = downloadService; this.downloadFileName = downloadFileName; this.widgetFactory = pageService.getWidgetFactory(); @@ -393,7 +398,7 @@ public class ExamForm implements TemplateComposer { .newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS) .withEntityKey(entityKey) - .withExec(ExamSEBRestrictionSettings.settingsFunction(this.pageService)) + .withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService)) .withAttribute( ExamSEBRestrictionSettings.PAGE_CONTEXT_ATTR_LMS_TYPE, this.restService.getBuilder(GetLmsSetup.class) @@ -406,13 +411,13 @@ public class ExamForm implements TemplateComposer { .newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION) .withEntityKey(entityKey) - .withExec(action -> ExamSEBRestrictionSettings.setSEBRestriction(action, true, this.restService)) + .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, true, this.restService)) .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData && BooleanUtils.isFalse(isRestricted)) .newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION) .withEntityKey(entityKey) - .withExec(action -> ExamSEBRestrictionSettings.setSEBRestriction(action, false, this.restService)) + .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService)) .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData && BooleanUtils.isTrue(isRestricted)); @@ -471,7 +476,7 @@ public class ExamForm implements TemplateComposer { .newAction(ActionDefinition.EXAM_CONFIGURATION_NEW) .withParentEntityKey(entityKey) - .withExec(ExamToConfigBindingForm.bindFunction(this.pageService)) + .withExec(this.examToConfigBindingForm.bindFunction()) .noEventPropagation() .publishIf(() -> modifyGrant && editable && !configurationTable.hasAnyContent()) @@ -590,7 +595,7 @@ public class ExamForm implements TemplateComposer { // when okay and the exam sebRestriction is true if (applySEBRestriction) { - ExamSEBRestrictionSettings.setSEBRestriction( + this.examSEBRestrictionSettings.setSEBRestriction( processFormSave, true, this.restService, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java index db82db77..03194813 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java @@ -95,11 +95,10 @@ public class ExamList implements TemplateComposer { protected ExamList( final PageService pageService, - final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; this.institutionFilter = new TableFilterAttribute( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamSEBRestrictionSettings.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamSEBRestrictionSettings.java index 660212c1..f3909586 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamSEBRestrictionSettings.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamSEBRestrictionSettings.java @@ -20,6 +20,8 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.widgets.Composite; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.API; @@ -28,6 +30,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Chapters; import ch.ethz.seb.sebserver.gbl.model.exam.OpenEdxSEBRestriction; import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gui.form.Form; @@ -47,6 +50,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetCourseCha import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetSEBRestriction; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveSEBRestriction; +@Lazy +@Component +@GuiProfile public class ExamSEBRestrictionSettings { private final static LocTextKey SEB_RESTRICTION_ERROR = @@ -73,7 +79,7 @@ public class ExamSEBRestrictionSettings { static final String PAGE_CONTEXT_ATTR_LMS_TYPE = "ATTR_LMS_TYPE"; - static Function settingsFunction(final PageService pageService) { + Function settingsFunction(final PageService pageService) { return action -> { @@ -104,7 +110,7 @@ public class ExamSEBRestrictionSettings { }; } - private static boolean doCreate( + private boolean doCreate( final PageService pageService, final PageContext pageContext, final FormHandle formHandle) { @@ -160,7 +166,7 @@ public class ExamSEBRestrictionSettings { .hasError(); } - private static final class SEBRestrictionPropertiesForm + private final class SEBRestrictionPropertiesForm implements ModalInputDialogComposer> { private final PageService pageService; @@ -290,7 +296,7 @@ public class ExamSEBRestrictionSettings { } - private static LmsType getLmsType(final PageContext pageContext) { + private LmsType getLmsType(final PageContext pageContext) { try { return LmsType.valueOf(pageContext.getAttribute(PAGE_CONTEXT_ATTR_LMS_TYPE)); } catch (final Exception e) { @@ -298,7 +304,7 @@ public class ExamSEBRestrictionSettings { } } - public static PageAction setSEBRestriction( + public PageAction setSEBRestriction( final PageAction action, final boolean activateRestriction, final RestService restService) { @@ -310,7 +316,7 @@ public class ExamSEBRestrictionSettings { error -> action.pageContext().notifyError(SEB_RESTRICTION_ERROR, error)); } - public static PageAction setSEBRestriction( + public PageAction setSEBRestriction( final PageAction action, final boolean activateRestriction, final RestService restService, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamToConfigBindingForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamToConfigBindingForm.java index 98cf8309..d7c37762 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamToConfigBindingForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamToConfigBindingForm.java @@ -16,6 +16,8 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.widgets.Composite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.EntityType; @@ -24,6 +26,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; +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.form.Form; @@ -45,7 +48,10 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewExamConfi import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExamConfigMapping; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; -final class ExamToConfigBindingForm { +@Lazy +@Component +@GuiProfile +public class ExamToConfigBindingForm { private static final Logger log = LoggerFactory.getLogger(ExamToConfigBindingForm.class); @@ -66,8 +72,13 @@ final class ExamToConfigBindingForm { private final static LocTextKey CONFIG_ACTION_NO_CONFIG_MESSAGE = new LocTextKey("sebserver.exam.configuration.action.noconfig.message"); - static Function bindFunction(final PageService pageService) { + private final PageService pageService; + protected ExamToConfigBindingForm(final PageService pageService) { + this.pageService = pageService; + } + + Function bindFunction() { return action -> { final PageContext pageContext = action.pageContext(); @@ -75,7 +86,7 @@ final class ExamToConfigBindingForm { final boolean isNew = entityKey == null; if (isNew) { - final boolean noConfigsAvailable = pageService.getResourceService() + final boolean noConfigsAvailable = this.pageService.getResourceService() .examConfigurationSelectionResources() .isEmpty(); @@ -87,15 +98,15 @@ final class ExamToConfigBindingForm { final ModalInputDialog> dialog = new ModalInputDialog>( action.pageContext().getParent().getShell(), - pageService.getWidgetFactory()) + this.pageService.getWidgetFactory()) .setLargeDialogWidth(); final BindFormContext bindFormContext = new BindFormContext( - pageService, + this.pageService, action.pageContext()); final Predicate> doBind = formHandle -> doCreate( - pageService, + this.pageService, pageContext, formHandle); @@ -114,7 +125,7 @@ final class ExamToConfigBindingForm { }; } - private static boolean doCreate( + private boolean doCreate( final PageService pageService, final PageContext pageContext, final FormHandle formHandle) { @@ -143,7 +154,7 @@ final class ExamToConfigBindingForm { .hasError(); } - private static final class BindFormContext implements ModalInputDialogComposer> { + private final class BindFormContext implements ModalInputDialogComposer> { private final PageService pageService; private final PageContext pageContext; @@ -244,7 +255,7 @@ final class ExamToConfigBindingForm { } } - private static void updateFormValuesFromConfigSelection(final Form form, final ResourceService resourceService) { + private void updateFormValuesFromConfigSelection(final Form form, final ResourceService resourceService) { final String configId = form.getFieldValue(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID); if (StringUtils.isBlank(configId)) { form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, null); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java index d07481f1..a7f47d5c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java @@ -71,12 +71,10 @@ public class IndicatorForm implements TemplateComposer { private final ResourceService resourceService; private final I18nSupport i18nSupport; - protected IndicatorForm( - final PageService pageService, - final ResourceService resourceService) { + protected IndicatorForm(final PageService pageService) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.i18nSupport = pageService.getI18nSupport(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java index 2fd79940..35359c94 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java @@ -57,14 +57,11 @@ public class InstitutionForm implements TemplateComposer { private final RestService restService; private final CurrentUser currentUser; - protected InstitutionForm( - final PageService pageService, - final RestService restService, - final CurrentUser currentUser) { + protected InstitutionForm(final PageService pageService) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java index 2a33e021..9b05b633 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java @@ -66,13 +66,11 @@ public class InstitutionList implements TemplateComposer { protected InstitutionList( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.pageSize = pageSize; this.activityFilter = new TableFilterAttribute( @@ -87,8 +85,8 @@ public class InstitutionList implements TemplateComposer { final Composite content = this.pageService .getWidgetFactory() .defaultPageLayout( - pageContext.getParent(), - TITLE_TEXT_KEY); + pageContext.getParent(), + TITLE_TEXT_KEY); final PageActionBuilder pageActionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java index 9845561d..4626aa1f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java @@ -104,12 +104,10 @@ public class LmsSetupForm implements TemplateComposer { private final PageService pageService; private final ResourceService resourceService; - protected LmsSetupForm( - final PageService pageService, - final ResourceService resourceService) { + protected LmsSetupForm(final PageService pageService) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java index 781759e5..0639f01c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java @@ -75,11 +75,10 @@ public class LmsSetupList implements TemplateComposer { protected LmsSetupList( final PageService pageService, - final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; this.institutionFilter = new TableFilterAttribute( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java index 310e3b3a..c1823377 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java @@ -95,7 +95,6 @@ public class MonitoringClientConnection implements TemplateComposer { protected MonitoringClientConnection( final ServerPushService serverPushService, final PageService pageService, - final ResourceService resourceService, final InstructionProcessor instructionProcessor, final SEBClientLogDetailsPopup sebClientLogDetailsPopup, @Value("${sebserver.gui.webservice.poll-interval:500}") final long pollInterval, @@ -103,8 +102,8 @@ public class MonitoringClientConnection implements TemplateComposer { this.serverPushService = serverPushService; this.pageService = pageService; - this.resourceService = resourceService; - this.i18nSupport = resourceService.getI18nSupport(); + this.resourceService = pageService.getResourceService(); + this.i18nSupport = this.resourceService.getI18nSupport(); this.instructionProcessor = instructionProcessor; this.pollInterval = pollInterval; this.sebClientLogDetailsPopup = sebClientLogDetailsPopup; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java index ae8c311d..7600b50d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java @@ -85,13 +85,12 @@ public class MonitoringRunningExam implements TemplateComposer { protected MonitoringRunningExam( final ServerPushService serverPushService, final PageService pageService, - final ResourceService resourceService, final InstructionProcessor instructionProcessor, @Value("${sebserver.gui.webservice.poll-interval:1000}") final long pollInterval) { this.serverPushService = serverPushService; this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.instructionProcessor = instructionProcessor; this.pollInterval = pollInterval; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java index 9ecc734e..a090c425 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java @@ -62,11 +62,10 @@ public class MonitoringRunningExamList implements TemplateComposer { protected MonitoringRunningExamList( final PageService pageService, - final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; this.typeFilter = new TableFilterAttribute( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java index 8f94aeaa..2cce042e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java @@ -117,12 +117,11 @@ public class QuizLookupList implements TemplateComposer { protected QuizLookupList( final PageService pageService, - final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; this.widgetFactory = pageService.getWidgetFactory(); - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; this.institutionFilter = new TableFilterAttribute( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java index d08b4a39..59c991be 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java @@ -115,14 +115,12 @@ public class SEBClientConfigForm implements TemplateComposer { protected SEBClientConfigForm( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, final DownloadService downloadService, @Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.downloadService = downloadService; this.downloadFileName = downloadFileName; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java index 37882509..a59b4b33 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java @@ -83,13 +83,11 @@ public class SEBClientConfigList implements TemplateComposer { protected SEBClientConfigList( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogDetailsPopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogDetailsPopup.java index 496f3649..a5b399e1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogDetailsPopup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogDetailsPopup.java @@ -8,6 +8,12 @@ package ch.ethz.seb.sebserver.gui.content; +import org.eclipse.swt.widgets.Composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.model.Domain; @@ -28,11 +34,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; -import org.eclipse.swt.widgets.Composite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; @Lazy @Component @@ -86,12 +87,10 @@ public class SEBClientLogDetailsPopup { private final I18nSupport i18nSupport; private final WidgetFactory widgetFactory; - public SEBClientLogDetailsPopup( - final PageService pageService, - final WidgetFactory widgetFactory) { + public SEBClientLogDetailsPopup(final PageService pageService) { this.pageService = pageService; - this.widgetFactory = widgetFactory; + this.widgetFactory = pageService.getWidgetFactory(); this.resourceService = pageService.getResourceService(); this.restService = pageService.getRestService(); this.i18nSupport = pageService.getI18nSupport(); @@ -124,7 +123,7 @@ public class SEBClientLogDetailsPopup { WidgetFactory.CustomVariant.TEXT_H3, DETAILS_EVENT_TILE_TEXT_KEY); - PageContext formContext = pc.copyOf(content); + final PageContext formContext = pc.copyOf(content); this.pageService.formBuilder(formContext) .withDefaultSpanInput(6) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigCreationPopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigCreationPopup.java index e9ebefe7..f9d9726a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigCreationPopup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigCreationPopup.java @@ -14,6 +14,8 @@ import java.util.function.Supplier; import org.apache.commons.lang3.BooleanUtils; import org.eclipse.swt.widgets.Composite; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; @@ -21,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigCreationInfo; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; +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.form.FormBuilder; @@ -35,7 +38,10 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.CopyConfiguration; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; -final class SEBExamConfigCreationPopup { +@Lazy +@Component +@GuiProfile +public class SEBExamConfigCreationPopup { static final LocTextKey FORM_COPY_TEXT_KEY = new LocTextKey("sebserver.examconfig.action.copy.dialog"); @@ -44,10 +50,13 @@ final class SEBExamConfigCreationPopup { static final LocTextKey FORM_CREATE_FROM_TEMPLATE_TEXT_KEY = new LocTextKey("sebserver.configtemplate.action.create-config.dialog"); - static Function configCreationFunction( - final PageService pageService, - final PageContext pageContext) { + private final PageService pageService; + protected SEBExamConfigCreationPopup(final PageService pageService) { + this.pageService = pageService; + } + + Function configCreationFunction(final PageContext pageContext) { final boolean copyAsTemplate = BooleanUtils.toBoolean( pageContext.getAttribute(PageContext.AttributeKeys.COPY_AS_TEMPLATE)); final boolean createFromTemplate = BooleanUtils.toBoolean( @@ -58,17 +67,17 @@ final class SEBExamConfigCreationPopup { final ModalInputDialog> dialog = new ModalInputDialog>( action.pageContext().getParent().getShell(), - pageService.getWidgetFactory()) + this.pageService.getWidgetFactory()) .setLargeDialogWidth(); final CreationFormContext formContext = new CreationFormContext( - pageService, + this.pageService, pageContext, copyAsTemplate, createFromTemplate); final Predicate> doCopy = formHandle -> doCreate( - pageService, + this.pageService, pageContext, copyAsTemplate, createFromTemplate, @@ -90,7 +99,7 @@ final class SEBExamConfigCreationPopup { }; } - private static boolean doCreate( + private boolean doCreate( final PageService pageService, final PageContext pageContext, final boolean copyAsTemplate, @@ -130,7 +139,7 @@ final class SEBExamConfigCreationPopup { return true; } - private static final class CreationFormContext implements ModalInputDialogComposer> { + private final class CreationFormContext implements ModalInputDialogComposer> { private final PageService pageService; private final PageContext pageContext; @@ -188,7 +197,5 @@ final class SEBExamConfigCreationPopup { return () -> formHandle; } - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java index 2895d0e4..f442d7cc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java @@ -103,19 +103,24 @@ public class SEBExamConfigForm implements TemplateComposer { private final PageService pageService; private final RestService restService; + private final SEBExamConfigCreationPopup sebExamConfigCreationPopup; + private final SEBExamConfigImportPopup sebExamConfigImportPopup; private final CurrentUser currentUser; private final DownloadService downloadService; private final String downloadFileName; protected SEBExamConfigForm( final PageService pageService, - final CurrentUser currentUser, + final SEBExamConfigCreationPopup sebExamConfigCreationPopup, + final SEBExamConfigImportPopup sebExamConfigImportPopup, final DownloadService downloadService, @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) { this.pageService = pageService; this.restService = pageService.getRestService(); - this.currentUser = currentUser; + this.sebExamConfigCreationPopup = sebExamConfigCreationPopup; + this.sebExamConfigImportPopup = sebExamConfigImportPopup; + this.currentUser = pageService.getCurrentUser(); this.downloadService = downloadService; this.downloadFileName = downloadFileName; } @@ -228,8 +233,7 @@ public class SEBExamConfigForm implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG) .withEntityKey(entityKey) - .withExec(SEBExamConfigCreationPopup.configCreationFunction( - this.pageService, + .withExec(this.sebExamConfigCreationPopup.configCreationFunction( actionContext .withEntityKey(entityKey) .withAttribute( @@ -243,8 +247,7 @@ public class SEBExamConfigForm implements TemplateComposer { .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .withEntityKey(entityKey) - .withExec(SEBExamConfigCreationPopup.configCreationFunction( - this.pageService, + .withExec(this.sebExamConfigCreationPopup.configCreationFunction( pageContext.withAttribute( PageContext.AttributeKeys.COPY_AS_TEMPLATE, Constants.TRUE_STRING))) @@ -272,7 +275,7 @@ public class SEBExamConfigForm implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG) .withEntityKey(entityKey) - .withExec(SEBExamConfigImportPopup.importFunction(this.pageService, false)) + .withExec(this.sebExamConfigImportPopup.importFunction(false)) .noEventPropagation() .publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigImportPopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigImportPopup.java index 100e4342..a09c1bc7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigImportPopup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigImportPopup.java @@ -19,6 +19,8 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; 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.APIMessage; @@ -27,6 +29,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; @@ -49,34 +52,39 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Im import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ImportNewExamConfig; import ch.ethz.seb.sebserver.gui.widget.FileUploadSelection; -final class SEBExamConfigImportPopup { +@Lazy +@Component +@GuiProfile +public class SEBExamConfigImportPopup { private static final Logger log = LoggerFactory.getLogger(SEBExamConfigImportPopup.class); private final static PageMessageException MISSING_PASSWORD = new PageMessageException( new LocTextKey("sebserver.examconfig.action.import.missing-password")); - static Function importFunction( - final PageService pageService, - final boolean newConfig) { + private final PageService pageService; + protected SEBExamConfigImportPopup(final PageService pageService) { + this.pageService = pageService; + } + + public Function importFunction(final boolean newConfig) { return action -> { final ModalInputDialog> dialog = new ModalInputDialog>( action.pageContext().getParent().getShell(), - pageService.getWidgetFactory()) + this.pageService.getWidgetFactory()) .setLargeDialogWidth(); final ImportFormContext importFormContext = new ImportFormContext( - pageService, + this.pageService, action.pageContext(), newConfig); dialog.open( SEBExamConfigForm.FORM_IMPORT_TEXT_KEY, (Predicate>) formHandle -> doImport( - pageService, formHandle, newConfig), importFormContext::cancelUpload, @@ -86,8 +94,7 @@ final class SEBExamConfigImportPopup { }; } - private static boolean doImport( - final PageService pageService, + private boolean doImport( final FormHandle formHandle, final boolean newConfig) { @@ -104,14 +111,14 @@ final class SEBExamConfigImportPopup { if (StringUtils.isBlank(fieldValue)) { form.setFieldError( Domain.CONFIGURATION_NODE.ATTR_NAME, - pageService + this.pageService .getI18nSupport() .getText(new LocTextKey("sebserver.form.validation.fieldError.notNull"))); return false; } else if (fieldValue.length() < 3 || fieldValue.length() > 255) { form.setFieldError( Domain.CONFIGURATION_NODE.ATTR_NAME, - pageService + this.pageService .getI18nSupport() .getText(new LocTextKey("sebserver.form.validation.fieldError.size", null, @@ -123,7 +130,7 @@ final class SEBExamConfigImportPopup { } else { // check if name already exists try { - if (pageService.getRestService() + if (this.pageService.getRestService() .getBuilder(GetExamConfigNodeNames.class) .call() .getOrThrow() @@ -134,7 +141,7 @@ final class SEBExamConfigImportPopup { form.setFieldError( Domain.CONFIGURATION_NODE.ATTR_NAME, - pageService + this.pageService .getI18nSupport() .getText(new LocTextKey( "sebserver.form.validation.fieldError.name.notunique"))); @@ -151,9 +158,9 @@ final class SEBExamConfigImportPopup { final InputStream inputStream = fileUpload.getInputStream(); if (inputStream != null) { final RestCall.RestCallBuilder restCall = (newConfig) - ? pageService.getRestService() + ? this.pageService.getRestService() .getBuilder(ImportNewExamConfig.class) - : pageService.getRestService() + : this.pageService.getRestService() .getBuilder(ImportExamConfigOnExistingConfig.class); restCall @@ -184,11 +191,11 @@ final class SEBExamConfigImportPopup { context.publishInfo(SEBExamConfigForm.FORM_IMPORT_CONFIRM_TEXT_KEY); if (newConfig) { - final PageAction action = pageService.pageActionBuilder(context) + final PageAction action = this.pageService.pageActionBuilder(context) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .create(); - pageService.firePageEvent( + this.pageService.firePageEvent( new ActionEvent(action), action.pageContext()); } @@ -233,7 +240,7 @@ final class SEBExamConfigImportPopup { } } - private static final class ImportFormContext implements ModalInputDialogComposer> { + private final class ImportFormContext implements ModalInputDialogComposer> { private final PageService pageService; private final PageContext pageContext; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java index 3b11f1d7..a9df221e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java @@ -28,7 +28,6 @@ import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; @@ -68,20 +67,19 @@ public class SEBExamConfigList implements TemplateComposer { private final TableFilterAttribute statusFilter; private final PageService pageService; - private final RestService restService; + private final SEBExamConfigImportPopup sebExamConfigImportPopup; private final CurrentUser currentUser; private final ResourceService resourceService; private final int pageSize; protected SEBExamConfigList( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, + final SEBExamConfigImportPopup sebExamConfigImportPopup, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.sebExamConfigImportPopup = sebExamConfigImportPopup; + this.currentUser = pageService.getCurrentUser(); this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; @@ -109,7 +107,7 @@ public class SEBExamConfigList implements TemplateComposer { // exam configuration table final EntityTable configTable = - this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) + this.pageService.entityTableBuilder(GetExamConfigNodePage.class) .withStaticFilter( Domain.CONFIGURATION_NODE.ATTR_TYPE, ConfigurationType.EXAM_CONFIG.name()) @@ -172,7 +170,7 @@ public class SEBExamConfigList implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .withSelect( configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), - SEBExamConfigImportPopup.importFunction(this.pageService, true), + this.sebExamConfigImportPopup.importFunction(true), EMPTY_SELECTION_TEXT_KEY) .noEventPropagation() .publishIf(examConfigGrant::im); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java index 614ca21c..0ca20d82 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java @@ -46,8 +46,8 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SEBExamConfigUndo; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -73,18 +73,19 @@ public class SEBSettingsForm implements TemplateComposer { private final PageService pageService; private final RestService restService; + private final SEBExamConfigCreationPopup sebExamConfigCreationPopup; private final CurrentUser currentUser; private final ExamConfigurationService examConfigurationService; protected SEBSettingsForm( final PageService pageService, - final RestService restService, - final CurrentUser currentUser, + final SEBExamConfigCreationPopup sebExamConfigCreationPopup, final ExamConfigurationService examConfigurationService) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.sebExamConfigCreationPopup = sebExamConfigCreationPopup; + this.currentUser = pageService.getCurrentUser(); this.examConfigurationService = examConfigurationService; } @@ -192,8 +193,7 @@ public class SEBSettingsForm implements TemplateComposer { .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .withEntityKey(entityKey) - .withExec(SEBExamConfigCreationPopup.configCreationFunction( - this.pageService, + .withExec(this.sebExamConfigCreationPopup.configCreationFunction( pageContext .withAttribute( PageContext.AttributeKeys.COPY_AS_TEMPLATE, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java index 8b939e7e..2b12bea3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountChangePasswordForm.java @@ -44,8 +44,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; * If the current user is the owner of the User-Account the password is required and must * match the users current password. * If the current user is an administrator that has to reset another users password the - * password that is also required must match the administrators current password. - **/ + * password that is also required must match the administrators current password. **/ public class UserAccountChangePasswordForm implements TemplateComposer { private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title"; @@ -61,14 +60,11 @@ public class UserAccountChangePasswordForm implements TemplateComposer { private final CurrentUser currentUser; private final I18nSupport i18nSupport; - protected UserAccountChangePasswordForm( - final PageService pageService, - final RestService restService, - final CurrentUser currentUser) { + protected UserAccountChangePasswordForm(final PageService pageService) { this.pageService = pageService; - this.restService = restService; - this.currentUser = currentUser; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); this.i18nSupport = pageService.getI18nSupport(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountDeletePopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountDeletePopup.java new file mode 100644 index 00000000..5f30d5e8 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountDeletePopup.java @@ -0,0 +1,188 @@ +/* + * 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.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.commons.lang3.BooleanUtils; +import org.eclipse.swt.widgets.Composite; +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.EntityType; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.form.Form; +import ch.ethz.seb.sebserver.gui.form.FormBuilder; +import ch.ethz.seb.sebserver.gui.form.FormHandle; +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.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.useraccount.GetUserAccount; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserDependency; + +@Lazy +@Component +@GuiProfile +public class UserAccountDeletePopup { + + private final static String ARG_WITH_CONFIGS = "WITH_CONFIGS"; + private final static String ARG_WITH_EXAMS = "WITH_EXAMS"; + + private final static LocTextKey FORM_TITLE = + new LocTextKey("sebserver.useraccount.delete.form.title"); + private final static LocTextKey FORM_INFO = + new LocTextKey("sebserver.useraccount.delete.form.info"); + private final static LocTextKey FORM_NAME = + new LocTextKey("sebserver.useraccount.delete.form.accountName"); + private final static LocTextKey FORM_CONFIGS = + new LocTextKey("sebserver.useraccount.delete.form.deleteAlsoConfigs"); + private final static LocTextKey FORM_EXAMS = + new LocTextKey("sebserver.useraccount.delete.form.deleteAlsoExams"); + private final static LocTextKey ACTION_DELETE = + new LocTextKey("sebserver.useraccount.delete.form.action.delete"); + private final static LocTextKey ACTION_REPORT = + new LocTextKey("sebserver.useraccount.delete.form.action.report"); + + private final PageService pageService; + + protected UserAccountDeletePopup(final PageService pageService) { + this.pageService = pageService; + } + + public Function deleteWizardFunction(final PageContext pageContext) { + return action -> { + + final ModelInputWizard wizard = + new ModelInputWizard( + action.pageContext().getParent().getShell(), + this.pageService.getWidgetFactory()) + .setLargeDialogWidth(); + + final String page1Id = "DELETE_PAGE"; + final String page2Id = "REPORT_PAGE"; + final Predicate callback = pc -> doDelete(this.pageService, pc); + final BiFunction> composePage1 = + (formHandle, content) -> composeDeleteDialog(content, pageContext); + final BiFunction> composePage2 = + (formHandle, content) -> composeReportDialog(content, pageContext); + + final WizardPage page1 = new WizardPage<>( + page1Id, + true, + composePage1, + new WizardAction<>(ACTION_DELETE, callback), + new WizardAction<>(ACTION_REPORT, page2Id)); + + final WizardPage 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) { + + final boolean withConfigs = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_CONFIGS)); + final boolean withExams = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_EXAMS)); + return true; + } + + private Supplier composeDeleteDialog( + final Composite parent, + final PageContext pageContext) { + + final EntityKey entityKey = pageContext.getEntityKey(); + final UserInfo userInfo = this.pageService.getRestService() + .getBuilder(GetUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) + .call() + .get(); + + final FormHandle formHandle = this.pageService.formBuilder( + pageContext.copyOf(parent)) + .readonly(false) + .addField(FormBuilder.text( + "USE_NAME", + FORM_NAME, + userInfo.toName().name) + .readonly(true)) + + .addField(FormBuilder.checkbox( + ARG_WITH_CONFIGS, + FORM_CONFIGS)) + + .addField(FormBuilder.checkbox( + ARG_WITH_EXAMS, + FORM_EXAMS)) + .build(); + + final Form form = formHandle.getForm(); + return () -> pageContext + .withAttribute(ARG_WITH_CONFIGS, form.getFieldValue(ARG_WITH_CONFIGS)) + .withAttribute(ARG_WITH_EXAMS, form.getFieldValue(ARG_WITH_EXAMS)); + } + + private Supplier composeReportDialog( + final Composite parent, + final PageContext pageContext) { + + // get selection + final boolean withConfigs = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_CONFIGS)); + final boolean withExams = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_EXAMS)); + + // get dependencies + final EntityKey entityKey = pageContext.getEntityKey(); + final RestCall>.RestCallBuilder restCallBuilder = this.pageService.getRestService() + .getBuilder(GetUserDependency.class) + .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId); + + if (withConfigs) { + restCallBuilder.withQueryParam( + API.PARAM_BULK_ACTION_INCLUDES, + EntityType.CONFIGURATION_NODE.name()); + } + if (withExams) { + restCallBuilder.withQueryParam( + API.PARAM_BULK_ACTION_INCLUDES, + EntityType.EXAM.name()); + } + +// final EntityTable configTable = +// this.pageService.entityTableBuilder(GetUserDependency.class) +// . + + final Set dependencies = restCallBuilder.call().getOrThrow(); + + // TODO get dependencies in case of selection and show all in a list (type / name) + + return () -> pageContext; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java index ceacd5f1..c8706cd9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java @@ -86,15 +86,17 @@ public class UserAccountForm implements TemplateComposer { private final PageService pageService; private final ResourceService resourceService; + private final UserAccountDeletePopup userAccountDeletePopup; private final boolean multilingual; protected UserAccountForm( final PageService pageService, - final ResourceService resourceService, + final UserAccountDeletePopup userAccountDeletePopup, @Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); + this.userAccountDeletePopup = userAccountDeletePopup; this.multilingual = BooleanUtils.toBoolean(multilingual); } @@ -266,6 +268,11 @@ public class UserAccountForm implements TemplateComposer { .withSimpleRestCall(restService, ActivateUserAccount.class) .publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive()) + .newAction(ActionDefinition.USER_ACCOUNT_DELETE) + .withEntityKey(entityKey) + .withExec(this.userAccountDeletePopup.deleteWizardFunction(pageContext)) + .publishIf(() -> (writeGrant || ownAccount) && readonly && institutionActive) + .newAction(ActionDefinition.USER_ACCOUNT_SAVE) .withEntityKey(entityKey) .withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost() @@ -289,4 +296,5 @@ public class UserAccountForm implements TemplateComposer { .withExec(this.pageService.backToCurrentFunction()) .publishIf(() -> !readonly); } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java index d5c8e42a..2d6690b7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java @@ -96,12 +96,11 @@ public class UserAccountList implements TemplateComposer { protected UserAccountList( final PageService pageService, - final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize, @Value("${sebserver.gui.multilingual:false}") final Boolean ml) { this.pageService = pageService; - this.resourceService = resourceService; + this.resourceService = pageService.getResourceService(); this.pageSize = pageSize; this.multilingual = BooleanUtils.isTrue(ml); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index bb34c320..8071b435 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -130,6 +130,11 @@ public enum ActionDefinition { ImageIcon.SWITCH, PageStateDefinitionImpl.USER_ACCOUNT_LIST, ActionCategory.USER_ACCOUNT_LIST), + USER_ACCOUNT_DELETE( + new LocTextKey("sebserver.useraccount.action.delete"), + ImageIcon.DELETE, + PageStateDefinitionImpl.USER_ACCOUNT_LIST, + ActionCategory.USER_ACCOUNT_LIST), USER_ACCOUNT_CHANGE_PASSWORD( new LocTextKey("sebserver.useraccount.action.change.password"), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java index c4b22b97..b851cf0f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java @@ -280,6 +280,15 @@ public interface PageService { * @return a FormBuilder instance for the given PageContext and with number of rows */ FormBuilder formBuilder(PageContext pageContext, int rows); + /** Get an new TableBuilder for specified page based RestCall. + * + * @param apiCall the SEB Server API RestCall that feeds the table with data + * @param the type of the Entity of the table + * @return TableBuilder of specified type */ + default TableBuilder entityTableBuilder(final Class>> apiCall) { + return entityTableBuilder(this.getRestService().getRestCall(apiCall)); + } + /** Get an new TableBuilder for specified page based RestCall. * * @param apiCall the SEB Server API RestCall that feeds the table with data diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java index cc4a41b9..9a9d591e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java @@ -38,11 +38,11 @@ public class ModalInputDialog extends Dialog { public static final int LARGE_DIALOG_WIDTH = 600; public static final int VERY_LARGE_DIALOG_WIDTH = 800; - private static final LocTextKey CANCEL_TEXT_KEY = + public static final LocTextKey CANCEL_TEXT_KEY = new LocTextKey("sebserver.overall.action.cancel"); - private static final LocTextKey OK_TEXT_KEY = + public static final LocTextKey OK_TEXT_KEY = new LocTextKey("sebserver.overall.action.ok"); - private static final LocTextKey CLOSE_TEXT_KEY = + public static final LocTextKey CLOSE_TEXT_KEY = new LocTextKey("sebserver.overall.action.close"); private final WidgetFactory widgetFactory; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModelInputWizard.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModelInputWizard.java new file mode 100644 index 00000000..9a4df5de --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModelInputWizard.java @@ -0,0 +1,234 @@ +/* + * 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.page.impl; + +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.eclipse.rap.rwt.RWT; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Shell; + +import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; +import ch.ethz.seb.sebserver.gui.service.page.PageService; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; + +public class ModelInputWizard extends Dialog { + + private static final long serialVersionUID = -3314062148477979319L; + + private final WidgetFactory widgetFactory; + private int dialogWidth = ModalInputDialog.DEFAULT_DIALOG_WIDTH; + private int dialogHeight = ModalInputDialog.DEFAULT_DIALOG_HEIGHT; + private int buttonWidth = ModalInputDialog.DEFAULT_DIALOG_BUTTON_WIDTH; + + public ModelInputWizard( + final Shell parent, + final WidgetFactory widgetFactory) { + + super(parent, SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL | SWT.CLOSE); + this.widgetFactory = widgetFactory; + } + + public ModelInputWizard setDialogWidth(final int dialogWidth) { + this.dialogWidth = dialogWidth; + return this; + } + + public ModelInputWizard setLargeDialogWidth() { + this.dialogWidth = ModalInputDialog.LARGE_DIALOG_WIDTH; + return this; + } + + public ModelInputWizard setVeryLargeDialogWidth() { + this.dialogWidth = ModalInputDialog.VERY_LARGE_DIALOG_WIDTH; + return this; + } + + public ModelInputWizard setDialogHeight(final int dialogHeight) { + this.dialogHeight = dialogHeight; + return this; + } + + public ModelInputWizard setButtonWidth(final int buttonWidth) { + this.buttonWidth = buttonWidth; + return this; + } + + @SafeVarargs + public final void open( + final LocTextKey title, + final Runnable cancelCallback, + final WizardPage... pages) { + + // Create the selection dialog window + final Shell shell = new Shell(getParent(), getStyle()); + shell.setText(getText()); + shell.setData(RWT.CUSTOM_VARIANT, CustomVariant.MESSAGE.key); + shell.setText(this.widgetFactory.getI18nSupport().getText(title)); + shell.setLayout(new GridLayout(1, true)); + final GridData gridData2 = new GridData(SWT.FILL, SWT.TOP, false, false); + shell.setLayoutData(gridData2); + + // the content composite + final Composite main = new Composite(shell, SWT.NONE); + main.setLayout(new GridLayout()); + final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.widthHint = this.dialogWidth; + main.setLayoutData(gridData); + + final Composite actionComp = new Composite(shell, SWT.NONE); + actionComp.setLayout(new GridLayout()); + actionComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + final Composite actionsComp = new Composite(actionComp, SWT.NONE); + actionsComp.setLayout(new RowLayout(SWT.HORIZONTAL)); + actionComp.setLayoutData(new GridData(SWT.TRAIL, SWT.FILL, true, true)); + + final List> pageList = Utils.immutableListOf(pages); + createPage(null, pageList, null, main, actionsComp); + + if (cancelCallback != null) { + final Button cancel = this.widgetFactory.buttonLocalized(actionsComp, ModalInputDialog.CANCEL_TEXT_KEY); + final RowData data = new RowData(); + data.width = this.buttonWidth; + cancel.setLayoutData(data); + cancel.addListener(SWT.Selection, event -> { + if (cancelCallback != null) { + cancelCallback.run(); + } + shell.close(); + }); + } + + gridData.heightHint = calcDialogHeight(main); + finishUp(shell); + } + + private void createPage( + final String pageId, + final List> pages, + final T valueFromPrevPage, + final Composite contentComp, + final Composite actionsComp) { + + final Optional> newPage = (pageId != null) + ? pages.stream() + .filter(p -> pageId.equals(p.id)) + .findFirst() + : pages.stream() + .filter(page -> page.isStart) + .findFirst(); + + if (newPage.isEmpty()) { + return; + } + + final WizardPage page = newPage.get(); + PageService.clearComposite(contentComp); + PageService.clearComposite(actionsComp); + + final Supplier valueSupplier = page.contentCompose.apply(valueFromPrevPage, contentComp); + + if (page.actions != null) { + for (final WizardAction action : page.actions) { + final Button actionButton = this.widgetFactory.buttonLocalized(actionsComp, action.name); + final RowData data = new RowData(); + data.width = this.buttonWidth; + actionButton.setLayoutData(data); + + actionButton.addListener(SWT.Selection, event -> { + if (valueSupplier != null) { + final T result = valueSupplier.get(); + if (action.toPage != null) { + createPage(action.toPage, pages, result, contentComp, actionsComp); + } else { + action.callback.test(result); + this.shell.close(); + } + } else { + this.shell.close(); + } + }); + } + } + } + + private void finishUp(final Shell shell) { + shell.pack(); + final Rectangle bounds = shell.getBounds(); + final Rectangle bounds2 = super.getParent().getDisplay().getBounds(); + bounds.x = (bounds2.width - bounds.width) / 2; + bounds.y = (bounds2.height - bounds.height) / 2; + shell.setBounds(bounds); + shell.open(); + } + + private int calcDialogHeight(final Composite main) { + final int actualHeight = main.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + final int displayHeight = main.getDisplay().getClientArea().height; + final int availableHeight = (displayHeight < actualHeight + 100) + ? displayHeight - 100 + : actualHeight; + return Math.min(availableHeight, this.dialogHeight); + } + + public static final class WizardPage { + public final String id; + public final boolean isStart; + public final BiFunction> contentCompose; + public final List> actions; + + @SafeVarargs + public WizardPage( + final String id, + final boolean isStart, + final BiFunction> contentCompose, + final WizardAction... actions) { + + this.id = id; + this.isStart = isStart; + this.contentCompose = contentCompose; + this.actions = Utils.asImmutableList(actions); + } + } + + public static final class WizardAction { + + public final LocTextKey name; + public final String toPage; + public final Predicate callback; + + public WizardAction(final LocTextKey name, final String toPage) { + this.name = name; + this.toPage = toPage; + this.callback = null; + } + + public WizardAction(final LocTextKey name, final Predicate callback) { + this.name = name; + this.toPage = null; + this.callback = callback; + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/GetExamDependencies.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/GetExamDependencies.java index bfb2a49d..1d6cc061 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/GetExamDependencies.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/GetExamDependencies.java @@ -19,20 +19,20 @@ 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.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; @Lazy @Component @GuiProfile -public class GetExamDependencies extends RestCall> { +public class GetExamDependencies extends RestCall> { public GetExamDependencies() { super(new TypeKey<>( CallType.GET_DEPENDENCIES, EntityType.EXAM, - new TypeReference>() { + new TypeReference>() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionDependency.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionDependency.java index 55c4ea31..4db18a09 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionDependency.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionDependency.java @@ -19,20 +19,20 @@ 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.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; @Lazy @Component @GuiProfile -public class GetInstitutionDependency extends RestCall> { +public class GetInstitutionDependency extends RestCall> { public GetInstitutionDependency() { super(new TypeKey<>( CallType.GET_DEPENDENCIES, EntityType.INSTITUTION, - new TypeReference>() { + new TypeReference>() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetupDependencies.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetupDependencies.java index addd22d1..59255eef 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetupDependencies.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetupDependencies.java @@ -19,20 +19,20 @@ 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.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; @Lazy @Component @GuiProfile -public class GetLmsSetupDependencies extends RestCall> { +public class GetLmsSetupDependencies extends RestCall> { public GetLmsSetupDependencies() { super(new TypeKey<>( CallType.GET_DEPENDENCIES, EntityType.LMS_SETUP, - new TypeReference>() { + new TypeReference>() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/useraccount/GetUserDependency.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/useraccount/GetUserDependency.java index a722f05b..b17a0cd8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/useraccount/GetUserDependency.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/useraccount/GetUserDependency.java @@ -19,20 +19,20 @@ 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.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; @Lazy @Component @GuiProfile -public class GetUserDependency extends RestCall> { +public class GetUserDependency extends RestCall> { public GetUserDependency() { super(new TypeKey<>( CallType.GET_DEPENDENCIES, EntityType.USER, - new TypeReference>() { + new TypeReference>() { }), HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index 529dcbf6..e64c5ca9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -80,8 +80,8 @@ public class EntityTable { final PageService pageService; final WidgetFactory widgetFactory; - final RestCall> restCall; - final Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter; + final PageSupplier pageSupplier; + final Function, PageSupplier.Builder> pageSupplierAdapter; final I18nSupport i18nSupport; final PageContext pageContext; @@ -109,7 +109,7 @@ public class EntityTable { final int type, final PageContext pageContext, final RestCall> restCall, - final Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter, + final Function, PageSupplier.Builder> pageSupplierAdapter, final PageService pageService, final List> columns, final int pageSize, @@ -132,8 +132,8 @@ public class EntityTable { this.i18nSupport = pageService.getI18nSupport(); this.pageContext = pageContext; this.widgetFactory = pageService.getWidgetFactory(); - this.restCall = restCall; - this.restCallAdapter = (restCallAdapter != null) ? restCallAdapter : Function.identity(); + this.pageSupplier = new RestCallPageSupplier<>(restCall); + this.pageSupplierAdapter = (pageSupplierAdapter != null) ? pageSupplierAdapter : Function.identity(); this.columns = Utils.immutableListOf(columns); this.emptyMessage = emptyMessage; this.hideNavigation = hideNavigation; @@ -233,8 +233,8 @@ public class EntityTable { } public EntityType getEntityType() { - if (this.restCall != null) { - return this.restCall.getEntityType(); + if (this.pageSupplier != null) { + return this.pageSupplier.getEntityType(); } return null; @@ -471,13 +471,13 @@ public class EntityTable { this.table.removeAll(); // get page data and create rows - this.restCall.newBuilder() + this.pageSupplier.newBuilder() .withPaging(pageNumber, pageSize) .withSorting(sortColumn, sortOrder) .withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null) .withQueryParams(this.staticQueryParams) - .apply(this.restCallAdapter) - .call() + .apply(this.pageSupplierAdapter) + .getPage() .map(this::createTableRowsFromPage) .map(this.navigator::update) .onError(this.pageContext::notifyUnexpectedError); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/PageSupplier.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/PageSupplier.java new file mode 100644 index 00000000..a899fc84 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/PageSupplier.java @@ -0,0 +1,43 @@ +/* + * 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.table; + +import java.util.function.Function; + +import org.springframework.util.MultiValueMap; + +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; +import ch.ethz.seb.sebserver.gbl.util.Result; + +public interface PageSupplier { + + EntityType getEntityType(); + + Builder newBuilder(); + + public interface Builder { + public Builder withPaging(final int pageNumber, final int pageSize); + + public Builder withSorting(final String column, final PageSortOrder order); + + public Builder withQueryParams(final MultiValueMap params); + + public Builder withQueryParam(String name, String value); + + public Builder withURIVariable(String name, String id); + + public Builder apply(final Function, Builder> f); + + public Result> getPage(); + + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/RestCallPageSupplier.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/RestCallPageSupplier.java new file mode 100644 index 00000000..7453dc5a --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/RestCallPageSupplier.java @@ -0,0 +1,82 @@ +/* + * 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.table; + +import java.util.function.Function; + +import org.springframework.util.MultiValueMap; + +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +public class RestCallPageSupplier implements PageSupplier { + + private final RestCall> restCall; + + protected RestCallPageSupplier(final RestCall> restCall) { + this.restCall = restCall; + } + + @Override + public EntityType getEntityType() { + return this.restCall.getEntityType(); + } + + @Override + public Builder newBuilder() { + final RestCall>.RestCallBuilder restCallBuilder = this.restCall.newBuilder(); + return new Builder<>() { + + @Override + public Builder withPaging(final int pageNumber, final int pageSize) { + restCallBuilder.withPaging(pageNumber, pageSize); + return this; + } + + @Override + public Builder withSorting(final String column, final PageSortOrder order) { + restCallBuilder.withSorting(column, order); + return this; + } + + @Override + public Builder withQueryParams(final MultiValueMap params) { + restCallBuilder.withQueryParams(params); + return this; + } + + @Override + public Builder withQueryParam(final String name, final String value) { + restCallBuilder.withQueryParam(name, value); + return this; + } + + @Override + public Builder withURIVariable(final String name, final String id) { + restCallBuilder.withURIVariable(name, id); + return this; + } + + @Override + public Builder apply(final Function, Builder> f) { + return f.apply(this); + } + + @Override + public Result> getPage() { + return restCallBuilder.call(); + } + + }; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java index 38df2298..20ca1e71 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java @@ -42,7 +42,7 @@ public class TableBuilder { private int pageSize = -1; private int type = SWT.NONE; private boolean hideNavigation = false; - private Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter; + private Function, PageSupplier.Builder> restCallAdapter; private BiConsumer rowDecorator; private Consumer> selectionListener; private boolean markupEnabled = false; @@ -94,7 +94,7 @@ public class TableBuilder { } public TableBuilder withRestCallAdapter( - final Function>.RestCallBuilder, RestCall>.RestCallBuilder> adapter) { + final Function, PageSupplier.Builder> adapter) { this.restCallAdapter = adapter; return this; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/BulkActionSupportDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/BulkActionSupportDAO.java index 0fda4bbc..0d66dad2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/BulkActionSupportDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/BulkActionSupportDAO.java @@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction; @@ -42,7 +43,7 @@ public interface BulkActionSupportDAO { * @param bulkAction the BulkAction to get keys of dependencies for the concrete type of this BulkActionSupportDAO * @return Collection of Result. Each Result refers to the EntityKey of processed entity or to an error if * happened */ - Set getDependencies(BulkAction bulkAction); + Set getDependencies(BulkAction bulkAction); /** This processed a given BulkAction for all entities of the concrete type of this BulkActionSupportDAO * that are defined by this given BulkAction. @@ -104,16 +105,16 @@ public interface BulkActionSupportDAO { /** Get dependency keys of all source entities of a given BulkAction * This method simply goes through all source EntityKeys of the given BulkAction - * and applies the selection functions for each, collecting the resulting dependency EntityKeys + * and applies the selection functions for each, collecting the resulting dependency EntityDependency * into one Set of all dependency keys for all source keys * * * @param bulkAction The BulkAction that defines the source keys * @param selectionFunction a selection functions that gives all dependency keys for a given source key - * @return Set of EntityKey instances that define all entities that depends on the given bulk action */ - default Set getDependencies( + * @return Set of EntityDependency instances that define all entities that depends on the given bulk action */ + default Set getDependencies( final BulkAction bulkAction, - final Function>> selectionFunction) { + final Function>> selectionFunction) { return bulkAction.sources .stream() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkAction.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkAction.java index e00dd0b1..bf814448 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkAction.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkAction.java @@ -19,6 +19,7 @@ import java.util.stream.Collectors; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; 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.user.UserLogActivityType; import ch.ethz.seb.sebserver.gbl.util.Result; @@ -40,7 +41,7 @@ public final class BulkAction { * Null means all dependencies are included (ignore) and empty means no dependencies are included */ public final EnumSet includeDependencies; /** A Set of EntityKey containing collected depending entities during dependency collection and processing phase */ - final Set dependencies; + final Set dependencies; /** A Set of EntityKey containing collected bulk action processing results during processing phase */ final Set> result; /** Indicates if this BulkAction has already been processed and is not valid anymore */ @@ -81,7 +82,7 @@ public final class BulkAction { return this.includeDependencies == null || this.includeDependencies.contains(type); } - public Set getDependencies() { + public Set getDependencies() { return Collections.unmodifiableSet(this.dependencies); } @@ -93,7 +94,8 @@ public final class BulkAction { if (!this.dependencies.isEmpty()) { return Collections.unmodifiableSet(new HashSet<>(this.dependencies .stream() - .filter(key -> key.entityType == type) + .filter(dependency -> dependency.self.entityType == type) + .map(dependency -> dependency.self) .collect(Collectors.toList()))); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java index 6ed3a5ed..9cceb6af 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java @@ -29,6 +29,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.JSONMapper; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry; @@ -184,13 +185,13 @@ public class BulkActionServiceImpl implements BulkActionService { return; } - for (final EntityKey key : action.dependencies) { + for (final EntityDependency dependency : action.dependencies) { this.userActivityLogDAO.log( activityType, - key.entityType, - key.modelId, - "Bulk Action - Dependency : " + toLogMessage(key)); + dependency.self.entityType, + dependency.self.modelId, + "Bulk Action - Dependency : " + toLogMessage(dependency)); } for (final EntityKey key : action.sources) { @@ -214,6 +215,18 @@ public class BulkActionServiceImpl implements BulkActionService { return entityAsString; } + private String toLogMessage(final EntityDependency dependency) { + String entityAsString; + try { + entityAsString = this.jsonMapper + .writerWithDefaultPrettyPrinter() + .writeValueAsString(dependency); + } catch (final JsonProcessingException e) { + entityAsString = dependency.toString(); + } + return entityAsString; + } + private List> getDependencySupporter(final BulkAction action) { switch (action.type) { case ACTIVATE: diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java index f4c07737..e5b2e858 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java @@ -26,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; 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.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; @@ -181,7 +182,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { } @Override - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // only for deletion if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { return Collections.emptySet(); @@ -192,7 +193,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { } // define the select function in case of source type - Function>> selectionFunction; + Function>> selectionFunction; switch (bulkAction.sourceType) { case INSTITUTION: selectionFunction = this::allIdsOfInstitution; @@ -317,20 +318,24 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { }); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample() .where( ClientConnectionRecordDynamicSqlSupport.institutionId, isEqualTo(Long.parseLong(institutionKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getId(), EntityType.CLIENT_CONNECTION), + rec.getExamUserSessionId(), + rec.getClientAddress())) .collect(Collectors.toList())); } - private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { - return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() + private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { + return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample() .leftJoin(ExamRecordDynamicSqlSupport.examRecord) .on( ExamRecordDynamicSqlSupport.id, @@ -341,12 +346,16 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION)) + .map(rec -> new EntityDependency( + lmsSetupKey, + new EntityKey(rec.getId(), EntityType.CLIENT_CONNECTION), + rec.getExamUserSessionId(), + rec.getClientAddress())) .collect(Collectors.toList())); } - private Result> allIdsOfUser(final EntityKey userKey) { - return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() + private Result> allIdsOfUser(final EntityKey userKey) { + return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample() .leftJoin(ExamRecordDynamicSqlSupport.examRecord) .on( ExamRecordDynamicSqlSupport.id, @@ -357,19 +366,27 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION)) + .map(rec -> new EntityDependency( + userKey, + new EntityKey(rec.getId(), EntityType.CLIENT_CONNECTION), + rec.getExamUserSessionId(), + rec.getClientAddress())) .collect(Collectors.toList())); } - private Result> allIdsOfExam(final EntityKey examKey) { - return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() + private Result> allIdsOfExam(final EntityKey examKey) { + return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample() .where( ClientConnectionRecordDynamicSqlSupport.examId, isEqualTo(Long.parseLong(examKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION)) + .map(rec -> new EntityDependency( + examKey, + new EntityKey(rec.getId(), EntityType.CLIENT_CONNECTION), + rec.getExamUserSessionId(), + rec.getClientAddress())) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java index 5ea06d07..84a6a9b8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java @@ -27,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; 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.ConfigCreationInfo; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; @@ -134,14 +135,14 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // only if included if (!bulkAction.includesDependencyType(EntityType.CONFIGURATION_NODE)) { return Collections.emptySet(); } // define the select function in case of source type - Function>> selectionFunction = + Function>> selectionFunction = key -> Result.of(Collections.emptyList()); if (bulkAction.sourceType == EntityType.INSTITUTION) { @@ -254,27 +255,35 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO { }); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectIdsByExample() + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectByExample() .where( ConfigurationNodeRecordDynamicSqlSupport.institutionId, isEqualTo(Long.valueOf(institutionKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CONFIGURATION_NODE)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getId(), EntityType.CONFIGURATION_NODE), + rec.getName(), + rec.getDescription())) .collect(Collectors.toList())); } - private Result> allIdsOfUser(final EntityKey userKey) { - return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectIdsByExample() + private Result> allIdsOfUser(final EntityKey userKey) { + return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectByExample() .where( ConfigurationNodeRecordDynamicSqlSupport.owner, isEqualTo(userKey.modelId)) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.CONFIGURATION_NODE)) + .map(rec -> new EntityDependency( + userKey, + new EntityKey(rec.getId(), EntityType.CONFIGURATION_NODE), + rec.getName(), + rec.getDescription())) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java index 845ce29c..6d21014e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java @@ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; @@ -280,7 +281,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // only deletion here if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { return Collections.emptySet(); @@ -291,7 +292,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { } // define the select function in case of source type - Function>> selectionFunction; + Function>> selectionFunction; switch (bulkAction.sourceType) { case INSTITUTION: selectionFunction = this::allIdsOfInstitution; @@ -361,6 +362,14 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { }); } + private Result> toDomainModel( + final Collection records) { + return Result.tryCatch(() -> records + .stream() + .map(model -> this.toDomainModel(model).getOrThrow()) + .collect(Collectors.toList())); + } + private Result toDomainModel(final ExamConfigurationMapRecord record) { return Result.tryCatch(() -> { @@ -420,81 +429,93 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { }); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() - .where( - ExamConfigurationMapRecordDynamicSqlSupport.institutionId, - isEqualTo(Long.valueOf(institutionKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) - .collect(Collectors.toList())); + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> toDependencies( + this.examConfigurationMapRecordMapper.selectByExample() + .where( + ExamConfigurationMapRecordDynamicSqlSupport.institutionId, + isEqualTo(Long.valueOf(institutionKey.modelId))) + .build() + .execute(), + institutionKey)); } - private Result> allIdsOfUser(final EntityKey userKey) { + private Result> allIdsOfUser(final EntityKey userKey) { return Result.tryCatch(() -> { - final List examsIds = this.examRecordMapper.selectByExample() + final List examsIds = this.examRecordMapper.selectIdsByExample() .where( ExamRecordDynamicSqlSupport.owner, isEqualTo(userKey.modelId)) .build() - .execute() - .stream() - .map(r -> r.getId()) - .collect(Collectors.toList()); + .execute(); - return this.examConfigurationMapRecordMapper.selectIdsByExample() - .where( - ExamConfigurationMapRecordDynamicSqlSupport.examId, - isIn(examsIds)) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) - .collect(Collectors.toList()); + return toDependencies( + this.examConfigurationMapRecordMapper.selectByExample() + .where( + ExamConfigurationMapRecordDynamicSqlSupport.examId, + isIn(examsIds)) + .build() + .execute(), + userKey); }); } - private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { - return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() - .leftJoin(ExamRecordDynamicSqlSupport.examRecord) - .on( - ExamRecordDynamicSqlSupport.id, - equalTo(ExamConfigurationMapRecordDynamicSqlSupport.examId)) + private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { + return Result.tryCatch(() -> toDependencies( + this.examConfigurationMapRecordMapper.selectByExample() + .leftJoin(ExamRecordDynamicSqlSupport.examRecord) + .on( + ExamRecordDynamicSqlSupport.id, + equalTo(ExamConfigurationMapRecordDynamicSqlSupport.examId)) - .where( - ExamRecordDynamicSqlSupport.lmsSetupId, - isEqualTo(Long.valueOf(lmsSetupKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) - .collect(Collectors.toList())); + .where( + ExamRecordDynamicSqlSupport.lmsSetupId, + isEqualTo(Long.valueOf(lmsSetupKey.modelId))) + .build() + .execute(), + lmsSetupKey)); } - private Result> allIdsOfExam(final EntityKey examKey) { - return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() - .where( - ExamConfigurationMapRecordDynamicSqlSupport.examId, - isEqualTo(Long.valueOf(examKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) - .collect(Collectors.toList())); + private Result> allIdsOfExam(final EntityKey examKey) { + return Result.tryCatch(() -> toDependencies( + this.examConfigurationMapRecordMapper.selectByExample() + .where( + ExamConfigurationMapRecordDynamicSqlSupport.examId, + isEqualTo(Long.valueOf(examKey.modelId))) + .build() + .execute(), + examKey)); } - private Result> allIdsOfConfig(final EntityKey configKey) { - return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() - .where( - ExamConfigurationMapRecordDynamicSqlSupport.configurationNodeId, - isEqualTo(Long.valueOf(configKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) - .collect(Collectors.toList())); + private Result> allIdsOfConfig(final EntityKey configKey) { + return Result.tryCatch(() -> toDependencies( + this.examConfigurationMapRecordMapper.selectByExample() + .where( + ExamConfigurationMapRecordDynamicSqlSupport.configurationNodeId, + isEqualTo(Long.valueOf(configKey.modelId))) + .build() + .execute(), + configKey)); + } + + private Collection toDependencies( + final List records, + final EntityKey parent) { + + return this.toDomainModel(records) + .map(models -> models + .stream() + .map(model -> getDependency(model, parent)) + .collect(Collectors.toList())) + .getOrThrow(); + } + + private EntityDependency getDependency(final ExamConfigurationMap model, final EntityKey parent) { + return new EntityDependency( + parent, + new EntityKey(model.getId(), EntityType.EXAM_CONFIGURATION_MAP), + model.getExamName() + " / " + model.getConfigName(), + model.getExamDescription() + " / " + model.getConfigDescription()); } private String getEncryptionPassword(final ExamConfigurationMap examConfigurationMap) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index 5f46ecd2..1cded3cb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -32,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.Constants; 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.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus; @@ -587,14 +588,14 @@ public class ExamDAOImpl implements ExamDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // only if included if (!bulkAction.includesDependencyType(EntityType.EXAM)) { return Collections.emptySet(); } // define the select function in case of source type - Function>> selectionFunction; + Function>> selectionFunction; switch (bulkAction.sourceType) { case INSTITUTION: selectionFunction = this::allIdsOfInstitution; @@ -636,37 +637,34 @@ public class ExamDAOImpl implements ExamDAO { .execute()); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() - .where(ExamRecordDynamicSqlSupport.institutionId, - isEqualTo(Long.valueOf(institutionKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM)) - .collect(Collectors.toList())); + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> toDependencies( + this.examRecordMapper.selectByExample() + .where(ExamRecordDynamicSqlSupport.institutionId, + isEqualTo(Long.valueOf(institutionKey.modelId))) + .build() + .execute(), + institutionKey)); } - private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { - return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() - .where(ExamRecordDynamicSqlSupport.lmsSetupId, - isEqualTo(Long.valueOf(lmsSetupKey.modelId))) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM)) - .collect(Collectors.toList())); + private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { + return Result.tryCatch(() -> toDependencies( + this.examRecordMapper.selectByExample() + .where(ExamRecordDynamicSqlSupport.lmsSetupId, + isEqualTo(Long.valueOf(lmsSetupKey.modelId))) + .build() + .execute(), + lmsSetupKey)); } - private Result> allIdsOfUser(final EntityKey userKey) { - return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() - .where(ExamRecordDynamicSqlSupport.owner, - isEqualTo(userKey.modelId)) - .build() - .execute() - .stream() - .map(id -> new EntityKey(id, EntityType.EXAM)) - .collect(Collectors.toList())); + private Result> allIdsOfUser(final EntityKey userKey) { + return Result.tryCatch(() -> toDependencies( + this.examRecordMapper.selectByExample() + .where(ExamRecordDynamicSqlSupport.owner, + isEqualTo(userKey.modelId)) + .build() + .execute(), + userKey)); } private Result recordById(final Long id) { @@ -681,6 +679,26 @@ public class ExamDAOImpl implements ExamDAO { }); } + private Collection toDependencies( + final List records, + final EntityKey parent) { + + return this.toDomainModel(records) + .map(models -> models + .stream() + .map(model -> getDependency(model, parent)) + .collect(Collectors.toList())) + .getOrThrow(); + } + + private EntityDependency getDependency(final Exam exam, final EntityKey parent) { + return new EntityDependency( + parent, + new EntityKey(exam.getId(), EntityType.EXAM), + exam.getName(), + exam.getDescription()); + } + private Result toDomainModelCached(final ExamRecord record) { return Result.tryCatch(() -> this.lmsAPIService .getLmsAPITemplate(record.getLmsSetupId()) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java index 431347f6..8fb01f99 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java @@ -27,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; 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.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType; @@ -220,7 +221,7 @@ public class IndicatorDAOImpl implements IndicatorDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // only for deletion if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { return Collections.emptySet(); @@ -231,7 +232,7 @@ public class IndicatorDAOImpl implements IndicatorDAO { } // define the select function in case of source type - Function>> selectionFunction; + Function>> selectionFunction; switch (bulkAction.sourceType) { case INSTITUTION: selectionFunction = this::allIdsOfInstitution; @@ -252,8 +253,8 @@ public class IndicatorDAOImpl implements IndicatorDAO { return getDependencies(bulkAction, selectionFunction); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample() .leftJoin(ExamRecordDynamicSqlSupport.examRecord) .on( ExamRecordDynamicSqlSupport.id, @@ -264,12 +265,16 @@ public class IndicatorDAOImpl implements IndicatorDAO { .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.INDICATOR)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getId(), EntityType.INDICATOR), + rec.getName(), + rec.getType())) .collect(Collectors.toList())); } - private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { - return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() + private Result> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { + return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample() .leftJoin(ExamRecordDynamicSqlSupport.examRecord) .on( ExamRecordDynamicSqlSupport.id, @@ -280,12 +285,16 @@ public class IndicatorDAOImpl implements IndicatorDAO { .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.INDICATOR)) + .map(rec -> new EntityDependency( + lmsSetupKey, + new EntityKey(rec.getId(), EntityType.INDICATOR), + rec.getName(), + rec.getType())) .collect(Collectors.toList())); } - private Result> allIdsOfUser(final EntityKey userKey) { - return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() + private Result> allIdsOfUser(final EntityKey userKey) { + return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample() .leftJoin(ExamRecordDynamicSqlSupport.examRecord) .on( ExamRecordDynamicSqlSupport.id, @@ -296,19 +305,27 @@ public class IndicatorDAOImpl implements IndicatorDAO { .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.INDICATOR)) + .map(rec -> new EntityDependency( + userKey, + new EntityKey(rec.getId(), EntityType.INDICATOR), + rec.getName(), + rec.getType())) .collect(Collectors.toList())); } - private Result> allIdsOfExam(final EntityKey examKey) { - return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() + private Result> allIdsOfExam(final EntityKey examKey) { + return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample() .where( IndicatorRecordDynamicSqlSupport.examId, isEqualTo(Long.parseLong(examKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.INDICATOR)) + .map(rec -> new EntityDependency( + examKey, + new EntityKey(rec.getId(), EntityType.INDICATOR), + rec.getName(), + rec.getType())) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java index e25c121e..03dab07e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java @@ -29,6 +29,7 @@ import org.springframework.transaction.annotation.Transactional; 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.institution.Institution; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -231,7 +232,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // NOTE since Institution is the top most Entity, there are no other Entity for that an Institution depends on. return Collections.emptySet(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java index 5a0e59b5..a3e7328d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java @@ -26,11 +26,12 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; +import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.client.ProxyData; -import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.model.institution.LmsSetup; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; @@ -137,7 +138,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { checkUniqueName(lmsSetup); - LmsSetupRecord savedRecord = recordById(lmsSetup.id) + final LmsSetupRecord savedRecord = recordById(lmsSetup.id) .getOrThrow(); final ClientCredentials lmsCredentials = createAPIClientCredentials(lmsSetup); @@ -250,7 +251,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // all of institution if (bulkAction.sourceType == EntityType.INSTITUTION) { return getDependencies(bulkAction, this::allIdsOfInstitution); @@ -306,14 +307,18 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { }); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.lmsSetupRecordMapper.selectIdsByExample() + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> this.lmsSetupRecordMapper.selectByExample() .where(LmsSetupRecordDynamicSqlSupport.institutionId, isEqualTo(Long.valueOf(institutionKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.LMS_SETUP)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getId(), EntityType.LMS_SETUP), + rec.getName(), + rec.getLmsUrl())) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/SEBClientConfigDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/SEBClientConfigDAOImpl.java index abf0523c..83aca519 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/SEBClientConfigDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/SEBClientConfigDAOImpl.java @@ -31,10 +31,11 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; +import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; -import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.model.sebconfig.SEBClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose; @@ -300,7 +301,7 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // all of institution if (bulkAction.sourceType == EntityType.INSTITUTION) { return getDependencies(bulkAction, this::allIdsOfInstitution); @@ -326,14 +327,18 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO { .map(SebClientConfigRecord::getEncryptSecret); } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { - return Result.tryCatch(() -> this.sebClientConfigRecordMapper.selectIdsByExample() + private Result> allIdsOfInstitution(final EntityKey institutionKey) { + return Result.tryCatch(() -> this.sebClientConfigRecordMapper.selectByExample() .where(SebClientConfigRecordDynamicSqlSupport.institutionId, isEqualTo(Long.valueOf(institutionKey.modelId))) .build() .execute() .stream() - .map(id -> new EntityKey(id, EntityType.SEB_CLIENT_CONFIGURATION)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getId(), EntityType.SEB_CLIENT_CONFIGURATION), + rec.getName(), + StringUtils.EMPTY)) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java index f4f913d4..e39baa56 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java @@ -42,6 +42,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.model.user.UserAccount; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; @@ -363,7 +364,7 @@ public class UserDAOImpl implements UserDAO { @Override @Transactional(readOnly = true) - public Set getDependencies(final BulkAction bulkAction) { + public Set getDependencies(final BulkAction bulkAction) { // all of institution if (bulkAction.sourceType == EntityType.INSTITUTION && (bulkAction.type == BulkActionType.DEACTIVATE || bulkAction.type == BulkActionType.HARD_DELETE)) { @@ -409,14 +410,18 @@ public class UserDAOImpl implements UserDAO { } } - private Result> allIdsOfInstitution(final EntityKey institutionKey) { + private Result> allIdsOfInstitution(final EntityKey institutionKey) { return Result.tryCatch(() -> this.userRecordMapper.selectByExample() .where(UserRecordDynamicSqlSupport.institutionId, isEqualTo(Long.valueOf(institutionKey.modelId))) .build() .execute() .stream() - .map(rec -> new EntityKey(rec.getUuid(), EntityType.USER)) + .map(rec -> new EntityDependency( + institutionKey, + new EntityKey(rec.getUuid(), EntityType.USER), + rec.getName(), + rec.getSurname())) .collect(Collectors.toList())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientConnectionController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientConnectionController.java index 95e07d79..1b4557d7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientConnectionController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientConnectionController.java @@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.RestController; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.EntityType; -import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -53,7 +53,7 @@ public class ClientConnectionController extends ReadonlyEntityController getDependencies( + public Collection getDependencies( final String modelId, final BulkActionType bulkActionType, final List includes) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java index bcbaccc3..e7f95998 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ClientEventController.java @@ -25,7 +25,7 @@ import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; -import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; @@ -115,7 +115,7 @@ public class ClientEventController extends ReadonlyEntityController getDependencies( + public Collection getDependencies( final String modelId, final BulkActionType bulkActionType, final List includes) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java index e2cca78c..cc56ea21 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java @@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; -import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityDependency; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; @@ -111,7 +111,7 @@ public class ConfigurationController extends ReadonlyEntityController getDependencies( + public Collection getDependencies( final String modelId, final BulkActionType bulkActionType, final List includes) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java index 830e1c1f..d92c818d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java @@ -37,6 +37,7 @@ 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; @@ -209,7 +210,7 @@ public abstract class EntityController { method = RequestMethod.GET, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - public Collection getDependencies( + public Collection getDependencies( @PathVariable final String modelId, @RequestParam(name = API.PARAM_BULK_ACTION_TYPE, required = true) final BulkActionType bulkActionType, @RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List includes) { diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index d730d86d..bb14db3b 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -255,6 +255,16 @@ sebserver.useraccount.form.password.new.tooltip=The new password for the user ac sebserver.useraccount.form.password.new.confirm=Confirm New Password sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password +sebserver.useraccount.delete.form.title=Delete User Account +sebserver.useraccount.delete.form.info=Delete this User Account with all dependencies. +sebserver.useraccount.delete.form.accountName=Name +sebserver.useraccount.delete.form.deleteAlsoConfigs=Include all Exam Configurations +sebserver.useraccount.delete.form.deleteAlsoConfigs.tooltip=This includes all Exam Configuration which this uses has created and is owner of +sebserver.useraccount.delete.form.deleteAlsoExams=Include all Exams +sebserver.useraccount.delete.form.deleteAlsoExams.tooltip=This includes all Exams which the user has imported and is owner of.
This also includes all Client Connections and all SEB Client Logs that where created within an Exam that is part of this deletion. +sebserver.useraccount.delete.form.action.delete=Delete +sebserver.useraccount.delete.form.action.report=Show Report + ################################ # LMS Setup ################################ diff --git a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java index cb385db4..0017a023 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java @@ -49,6 +49,7 @@ import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION; +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; @@ -2216,7 +2217,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { .findFirst() .get(); - List dependencies = restService.getBuilder(GetUserDependency.class) + List dependencies = restService.getBuilder(GetUserDependency.class) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .call() @@ -2238,27 +2239,27 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { + "EXAM_CONFIGURATION_MAP, " + "INDICATOR, " + "INDICATOR]", - dependencies.stream().map(EntityKey::getEntityType).collect(Collectors.toList()).toString()); + dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); // check that the user is owner of all depending exams and configurations dependencies.stream() - .filter(key -> key.entityType == EntityType.EXAM) + .filter(key -> key.self.entityType == EntityType.EXAM) .forEach(key -> { assertEquals( user.modelId, restService.getBuilder(GetExam.class) - .withURIVariable(API.PARAM_MODEL_ID, key.getModelId()) + .withURIVariable(API.PARAM_MODEL_ID, key.self.getModelId()) .call() .getOrThrow().owner); }); dependencies.stream() - .filter(key -> key.entityType == EntityType.CONFIGURATION_NODE) + .filter(key -> key.self.entityType == EntityType.CONFIGURATION_NODE) .forEach(key -> { assertEquals( user.modelId, restService.getBuilder(GetExamConfigNode.class) - .withURIVariable(API.PARAM_MODEL_ID, key.getModelId()) + .withURIVariable(API.PARAM_MODEL_ID, key.self.getModelId()) .call() .getOrThrow().owner); }); @@ -2283,7 +2284,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { + "EXAM_CONFIGURATION_MAP, " + "INDICATOR, " + "INDICATOR]", - dependencies.stream().map(EntityKey::getEntityType).collect(Collectors.toList()).toString()); + dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); // only with configuration dependencies dependencies = restService.getBuilder(GetUserDependency.class) @@ -2301,7 +2302,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { + "CONFIGURATION_NODE, " + "CONFIGURATION_NODE, " + "CONFIGURATION_NODE]", - dependencies.stream().map(EntityKey::getEntityType).collect(Collectors.toList()).toString()); + dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); // only with exam and configuration dependencies dependencies = restService.getBuilder(GetUserDependency.class) @@ -2328,7 +2329,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { + "EXAM_CONFIGURATION_MAP, " + "INDICATOR, " + "INDICATOR]", - dependencies.stream().map(EntityKey::getEntityType).collect(Collectors.toList()).toString()); + dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString()); } @Test diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/InstitutionAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/InstitutionAPITest.java index 0b70275d..83820aba 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/InstitutionAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/InstitutionAPITest.java @@ -14,6 +14,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.junit.Test; import org.springframework.http.HttpMethod; @@ -27,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.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; @@ -404,21 +406,23 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { @Test public void testDependency() throws Exception { - final Collection dependencies = new RestAPITestHelper() + final Collection dependencies = new RestAPITestHelper() .withAccessToken(getSebAdminAccess()) .withPath(API.INSTITUTION_ENDPOINT) .withPath("1") .withPath(API.DEPENDENCY_PATH_SEGMENT) .withAttribute(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name()) .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference>() { + .getAsObject(new TypeReference>() { }); + final List depKeys = dependencies.stream().map(dep -> dep.self).collect(Collectors.toList()); + assertNotNull(dependencies); assertTrue(dependencies.size() == 3); - assertTrue(dependencies.contains(new EntityKey("user1", EntityType.USER))); - assertTrue(dependencies.contains(new EntityKey("user2", EntityType.USER))); - assertTrue(dependencies.contains(new EntityKey("user5", EntityType.USER))); + assertTrue(depKeys.contains(new EntityKey("user1", EntityType.USER))); + assertTrue(depKeys.contains(new EntityKey("user2", EntityType.USER))); + assertTrue(depKeys.contains(new EntityKey("user5", EntityType.USER))); } static void assertContainsInstitution(final String name, final Collection institutions) {