SEBSERV-10 GUI implementation

This commit is contained in:
anhefti 2020-07-14 15:25:42 +02:00
parent e5025e1c47
commit f61b142cc7
60 changed files with 1172 additions and 351 deletions

View file

@ -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<EntityDependency> {
@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;
}
}
}

View file

@ -78,13 +78,11 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
protected ConfigTemplateAttributeForm( protected ConfigTemplateAttributeForm(
final PageService pageService, final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;

View file

@ -80,6 +80,7 @@ public class ConfigTemplateForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final SEBExamConfigCreationPopup sebxamConfigCreationPopup;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
private final ResourceService resourceService; private final ResourceService resourceService;
private final ExamConfigurationService examConfigurationService; private final ExamConfigurationService examConfigurationService;
@ -91,16 +92,16 @@ public class ConfigTemplateForm implements TemplateComposer {
protected ConfigTemplateForm( protected ConfigTemplateForm(
final PageService pageService, final PageService pageService,
final RestService restService, final SEBExamConfigCreationPopup sebxamConfigCreationPopup,
final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;
this.sebxamConfigCreationPopup = sebxamConfigCreationPopup;
} }
@ -292,8 +293,7 @@ public class ConfigTemplateForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SEBExamConfigCreationPopup.configCreationFunction( .withExec(this.sebxamConfigCreationPopup.configCreationFunction(
this.pageService,
pageContext pageContext
.withAttribute( .withAttribute(
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE, PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,

View file

@ -72,13 +72,11 @@ public class ConfigTemplateList implements TemplateComposer {
protected ConfigTemplateList( protected ConfigTemplateList(
final PageService pageService, final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;

View file

@ -162,6 +162,8 @@ public class ExamForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
private final ExamSEBRestrictionSettings examSEBRestrictionSettings;
private final ExamToConfigBindingForm examToConfigBindingForm;
private final DownloadService downloadService; private final DownloadService downloadService;
private final String downloadFileName; private final String downloadFileName;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
@ -169,12 +171,15 @@ public class ExamForm implements TemplateComposer {
protected ExamForm( protected ExamForm(
final PageService pageService, final PageService pageService,
final ResourceService resourceService, final ExamSEBRestrictionSettings examSEBRestrictionSettings,
final ExamToConfigBindingForm examToConfigBindingForm,
final DownloadService downloadService, final DownloadService downloadService,
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) { @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.examSEBRestrictionSettings = examSEBRestrictionSettings;
this.examToConfigBindingForm = examToConfigBindingForm;
this.downloadService = downloadService; this.downloadService = downloadService;
this.downloadFileName = downloadFileName; this.downloadFileName = downloadFileName;
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
@ -393,7 +398,7 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS) .newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(ExamSEBRestrictionSettings.settingsFunction(this.pageService)) .withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService))
.withAttribute( .withAttribute(
ExamSEBRestrictionSettings.PAGE_CONTEXT_ATTR_LMS_TYPE, ExamSEBRestrictionSettings.PAGE_CONTEXT_ATTR_LMS_TYPE,
this.restService.getBuilder(GetLmsSetup.class) this.restService.getBuilder(GetLmsSetup.class)
@ -406,13 +411,13 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION) .newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> ExamSEBRestrictionSettings.setSEBRestriction(action, true, this.restService)) .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, true, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isFalse(isRestricted)) && BooleanUtils.isFalse(isRestricted))
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION) .newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> ExamSEBRestrictionSettings.setSEBRestriction(action, false, this.restService)) .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isTrue(isRestricted)); && BooleanUtils.isTrue(isRestricted));
@ -471,7 +476,7 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_CONFIGURATION_NEW) .newAction(ActionDefinition.EXAM_CONFIGURATION_NEW)
.withParentEntityKey(entityKey) .withParentEntityKey(entityKey)
.withExec(ExamToConfigBindingForm.bindFunction(this.pageService)) .withExec(this.examToConfigBindingForm.bindFunction())
.noEventPropagation() .noEventPropagation()
.publishIf(() -> modifyGrant && editable && !configurationTable.hasAnyContent()) .publishIf(() -> modifyGrant && editable && !configurationTable.hasAnyContent())
@ -590,7 +595,7 @@ public class ExamForm implements TemplateComposer {
// when okay and the exam sebRestriction is true // when okay and the exam sebRestriction is true
if (applySEBRestriction) { if (applySEBRestriction) {
ExamSEBRestrictionSettings.setSEBRestriction( this.examSEBRestrictionSettings.setSEBRestriction(
processFormSave, processFormSave,
true, true,
this.restService, this.restService,

View file

@ -95,11 +95,10 @@ public class ExamList implements TemplateComposer {
protected ExamList( protected ExamList(
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(

View file

@ -20,6 +20,8 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; 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.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; 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.OpenEdxSEBRestriction;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction; 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.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.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.form.Form; 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.GetSEBRestriction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveSEBRestriction; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveSEBRestriction;
@Lazy
@Component
@GuiProfile
public class ExamSEBRestrictionSettings { public class ExamSEBRestrictionSettings {
private final static LocTextKey SEB_RESTRICTION_ERROR = 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 final String PAGE_CONTEXT_ATTR_LMS_TYPE = "ATTR_LMS_TYPE";
static Function<PageAction, PageAction> settingsFunction(final PageService pageService) { Function<PageAction, PageAction> settingsFunction(final PageService pageService) {
return action -> { return action -> {
@ -104,7 +110,7 @@ public class ExamSEBRestrictionSettings {
}; };
} }
private static boolean doCreate( private boolean doCreate(
final PageService pageService, final PageService pageService,
final PageContext pageContext, final PageContext pageContext,
final FormHandle<?> formHandle) { final FormHandle<?> formHandle) {
@ -160,7 +166,7 @@ public class ExamSEBRestrictionSettings {
.hasError(); .hasError();
} }
private static final class SEBRestrictionPropertiesForm private final class SEBRestrictionPropertiesForm
implements ModalInputDialogComposer<FormHandle<?>> { implements ModalInputDialogComposer<FormHandle<?>> {
private final PageService pageService; 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 { try {
return LmsType.valueOf(pageContext.getAttribute(PAGE_CONTEXT_ATTR_LMS_TYPE)); return LmsType.valueOf(pageContext.getAttribute(PAGE_CONTEXT_ATTR_LMS_TYPE));
} catch (final Exception e) { } catch (final Exception e) {
@ -298,7 +304,7 @@ public class ExamSEBRestrictionSettings {
} }
} }
public static PageAction setSEBRestriction( public PageAction setSEBRestriction(
final PageAction action, final PageAction action,
final boolean activateRestriction, final boolean activateRestriction,
final RestService restService) { final RestService restService) {
@ -310,7 +316,7 @@ public class ExamSEBRestrictionSettings {
error -> action.pageContext().notifyError(SEB_RESTRICTION_ERROR, error)); error -> action.pageContext().notifyError(SEB_RESTRICTION_ERROR, error));
} }
public static PageAction setSEBRestriction( public PageAction setSEBRestriction(
final PageAction action, final PageAction action,
final boolean activateRestriction, final boolean activateRestriction,
final RestService restService, final RestService restService,

View file

@ -16,6 +16,8 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.Form; 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.exam.SaveExamConfigMapping;
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.GetExamConfigNode;
final class ExamToConfigBindingForm { @Lazy
@Component
@GuiProfile
public class ExamToConfigBindingForm {
private static final Logger log = LoggerFactory.getLogger(ExamToConfigBindingForm.class); 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 = private final static LocTextKey CONFIG_ACTION_NO_CONFIG_MESSAGE =
new LocTextKey("sebserver.exam.configuration.action.noconfig.message"); new LocTextKey("sebserver.exam.configuration.action.noconfig.message");
static Function<PageAction, PageAction> bindFunction(final PageService pageService) { private final PageService pageService;
protected ExamToConfigBindingForm(final PageService pageService) {
this.pageService = pageService;
}
Function<PageAction, PageAction> bindFunction() {
return action -> { return action -> {
final PageContext pageContext = action.pageContext(); final PageContext pageContext = action.pageContext();
@ -75,7 +86,7 @@ final class ExamToConfigBindingForm {
final boolean isNew = entityKey == null; final boolean isNew = entityKey == null;
if (isNew) { if (isNew) {
final boolean noConfigsAvailable = pageService.getResourceService() final boolean noConfigsAvailable = this.pageService.getResourceService()
.examConfigurationSelectionResources() .examConfigurationSelectionResources()
.isEmpty(); .isEmpty();
@ -87,15 +98,15 @@ final class ExamToConfigBindingForm {
final ModalInputDialog<FormHandle<ExamConfigurationMap>> dialog = final ModalInputDialog<FormHandle<ExamConfigurationMap>> dialog =
new ModalInputDialog<FormHandle<ExamConfigurationMap>>( new ModalInputDialog<FormHandle<ExamConfigurationMap>>(
action.pageContext().getParent().getShell(), action.pageContext().getParent().getShell(),
pageService.getWidgetFactory()) this.pageService.getWidgetFactory())
.setLargeDialogWidth(); .setLargeDialogWidth();
final BindFormContext bindFormContext = new BindFormContext( final BindFormContext bindFormContext = new BindFormContext(
pageService, this.pageService,
action.pageContext()); action.pageContext());
final Predicate<FormHandle<ExamConfigurationMap>> doBind = formHandle -> doCreate( final Predicate<FormHandle<ExamConfigurationMap>> doBind = formHandle -> doCreate(
pageService, this.pageService,
pageContext, pageContext,
formHandle); formHandle);
@ -114,7 +125,7 @@ final class ExamToConfigBindingForm {
}; };
} }
private static boolean doCreate( private boolean doCreate(
final PageService pageService, final PageService pageService,
final PageContext pageContext, final PageContext pageContext,
final FormHandle<ExamConfigurationMap> formHandle) { final FormHandle<ExamConfigurationMap> formHandle) {
@ -143,7 +154,7 @@ final class ExamToConfigBindingForm {
.hasError(); .hasError();
} }
private static final class BindFormContext implements ModalInputDialogComposer<FormHandle<ExamConfigurationMap>> { private final class BindFormContext implements ModalInputDialogComposer<FormHandle<ExamConfigurationMap>> {
private final PageService pageService; private final PageService pageService;
private final PageContext pageContext; 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); final String configId = form.getFieldValue(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
if (StringUtils.isBlank(configId)) { if (StringUtils.isBlank(configId)) {
form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, null); form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, null);

View file

@ -71,12 +71,10 @@ public class IndicatorForm implements TemplateComposer {
private final ResourceService resourceService; private final ResourceService resourceService;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
protected IndicatorForm( protected IndicatorForm(final PageService pageService) {
final PageService pageService,
final ResourceService resourceService) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
} }

View file

@ -57,14 +57,11 @@ public class InstitutionForm implements TemplateComposer {
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
protected InstitutionForm( protected InstitutionForm(final PageService pageService) {
final PageService pageService,
final RestService restService,
final CurrentUser currentUser) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
} }
@Override @Override

View file

@ -66,13 +66,11 @@ public class InstitutionList implements TemplateComposer {
protected InstitutionList( protected InstitutionList(
final PageService pageService, final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.pageSize = pageSize; this.pageSize = pageSize;
this.activityFilter = new TableFilterAttribute( this.activityFilter = new TableFilterAttribute(
@ -87,8 +85,8 @@ public class InstitutionList implements TemplateComposer {
final Composite content = this.pageService final Composite content = this.pageService
.getWidgetFactory() .getWidgetFactory()
.defaultPageLayout( .defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_TEXT_KEY);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());

View file

@ -104,12 +104,10 @@ public class LmsSetupForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
protected LmsSetupForm( protected LmsSetupForm(final PageService pageService) {
final PageService pageService,
final ResourceService resourceService) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
} }
@Override @Override

View file

@ -75,11 +75,10 @@ public class LmsSetupList implements TemplateComposer {
protected LmsSetupList( protected LmsSetupList(
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(

View file

@ -95,7 +95,6 @@ public class MonitoringClientConnection implements TemplateComposer {
protected MonitoringClientConnection( protected MonitoringClientConnection(
final ServerPushService serverPushService, final ServerPushService serverPushService,
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
final InstructionProcessor instructionProcessor, final InstructionProcessor instructionProcessor,
final SEBClientLogDetailsPopup sebClientLogDetailsPopup, final SEBClientLogDetailsPopup sebClientLogDetailsPopup,
@Value("${sebserver.gui.webservice.poll-interval:500}") final long pollInterval, @Value("${sebserver.gui.webservice.poll-interval:500}") final long pollInterval,
@ -103,8 +102,8 @@ public class MonitoringClientConnection implements TemplateComposer {
this.serverPushService = serverPushService; this.serverPushService = serverPushService;
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.i18nSupport = resourceService.getI18nSupport(); this.i18nSupport = this.resourceService.getI18nSupport();
this.instructionProcessor = instructionProcessor; this.instructionProcessor = instructionProcessor;
this.pollInterval = pollInterval; this.pollInterval = pollInterval;
this.sebClientLogDetailsPopup = sebClientLogDetailsPopup; this.sebClientLogDetailsPopup = sebClientLogDetailsPopup;

View file

@ -85,13 +85,12 @@ public class MonitoringRunningExam implements TemplateComposer {
protected MonitoringRunningExam( protected MonitoringRunningExam(
final ServerPushService serverPushService, final ServerPushService serverPushService,
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
final InstructionProcessor instructionProcessor, final InstructionProcessor instructionProcessor,
@Value("${sebserver.gui.webservice.poll-interval:1000}") final long pollInterval) { @Value("${sebserver.gui.webservice.poll-interval:1000}") final long pollInterval) {
this.serverPushService = serverPushService; this.serverPushService = serverPushService;
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.instructionProcessor = instructionProcessor; this.instructionProcessor = instructionProcessor;
this.pollInterval = pollInterval; this.pollInterval = pollInterval;
} }

View file

@ -62,11 +62,10 @@ public class MonitoringRunningExamList implements TemplateComposer {
protected MonitoringRunningExamList( protected MonitoringRunningExamList(
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.typeFilter = new TableFilterAttribute( this.typeFilter = new TableFilterAttribute(

View file

@ -117,12 +117,11 @@ public class QuizLookupList implements TemplateComposer {
protected QuizLookupList( protected QuizLookupList(
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(

View file

@ -115,14 +115,12 @@ public class SEBClientConfigForm implements TemplateComposer {
protected SEBClientConfigForm( protected SEBClientConfigForm(
final PageService pageService, final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
final DownloadService downloadService, final DownloadService downloadService,
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) { @Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.downloadService = downloadService; this.downloadService = downloadService;
this.downloadFileName = downloadFileName; this.downloadFileName = downloadFileName;
} }

View file

@ -83,13 +83,11 @@ public class SEBClientConfigList implements TemplateComposer {
protected SEBClientConfigList( protected SEBClientConfigList(
final PageService pageService, final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;

View file

@ -8,6 +8,12 @@
package ch.ethz.seb.sebserver.gui.content; 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.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain; 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.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; 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 @Lazy
@Component @Component
@ -86,12 +87,10 @@ public class SEBClientLogDetailsPopup {
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
public SEBClientLogDetailsPopup( public SEBClientLogDetailsPopup(final PageService pageService) {
final PageService pageService,
final WidgetFactory widgetFactory) {
this.pageService = pageService; this.pageService = pageService;
this.widgetFactory = widgetFactory; this.widgetFactory = pageService.getWidgetFactory();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.restService = pageService.getRestService(); this.restService = pageService.getRestService();
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
@ -124,7 +123,7 @@ public class SEBClientLogDetailsPopup {
WidgetFactory.CustomVariant.TEXT_H3, WidgetFactory.CustomVariant.TEXT_H3,
DETAILS_EVENT_TILE_TEXT_KEY); DETAILS_EVENT_TILE_TEXT_KEY);
PageContext formContext = pc.copyOf(content); final PageContext formContext = pc.copyOf(content);
this.pageService.formBuilder(formContext) this.pageService.formBuilder(formContext)
.withDefaultSpanInput(6) .withDefaultSpanInput(6)

View file

@ -14,6 +14,8 @@ import java.util.function.Supplier;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.eclipse.swt.widgets.Composite; 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.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; 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.ConfigCreationInfo;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; 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.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.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; 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.CopyConfiguration;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; 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 = static final LocTextKey FORM_COPY_TEXT_KEY =
new LocTextKey("sebserver.examconfig.action.copy.dialog"); new LocTextKey("sebserver.examconfig.action.copy.dialog");
@ -44,10 +50,13 @@ final class SEBExamConfigCreationPopup {
static final LocTextKey FORM_CREATE_FROM_TEMPLATE_TEXT_KEY = static final LocTextKey FORM_CREATE_FROM_TEMPLATE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.action.create-config.dialog"); new LocTextKey("sebserver.configtemplate.action.create-config.dialog");
static Function<PageAction, PageAction> configCreationFunction( private final PageService pageService;
final PageService pageService,
final PageContext pageContext) {
protected SEBExamConfigCreationPopup(final PageService pageService) {
this.pageService = pageService;
}
Function<PageAction, PageAction> configCreationFunction(final PageContext pageContext) {
final boolean copyAsTemplate = BooleanUtils.toBoolean( final boolean copyAsTemplate = BooleanUtils.toBoolean(
pageContext.getAttribute(PageContext.AttributeKeys.COPY_AS_TEMPLATE)); pageContext.getAttribute(PageContext.AttributeKeys.COPY_AS_TEMPLATE));
final boolean createFromTemplate = BooleanUtils.toBoolean( final boolean createFromTemplate = BooleanUtils.toBoolean(
@ -58,17 +67,17 @@ final class SEBExamConfigCreationPopup {
final ModalInputDialog<FormHandle<ConfigCreationInfo>> dialog = final ModalInputDialog<FormHandle<ConfigCreationInfo>> dialog =
new ModalInputDialog<FormHandle<ConfigCreationInfo>>( new ModalInputDialog<FormHandle<ConfigCreationInfo>>(
action.pageContext().getParent().getShell(), action.pageContext().getParent().getShell(),
pageService.getWidgetFactory()) this.pageService.getWidgetFactory())
.setLargeDialogWidth(); .setLargeDialogWidth();
final CreationFormContext formContext = new CreationFormContext( final CreationFormContext formContext = new CreationFormContext(
pageService, this.pageService,
pageContext, pageContext,
copyAsTemplate, copyAsTemplate,
createFromTemplate); createFromTemplate);
final Predicate<FormHandle<ConfigCreationInfo>> doCopy = formHandle -> doCreate( final Predicate<FormHandle<ConfigCreationInfo>> doCopy = formHandle -> doCreate(
pageService, this.pageService,
pageContext, pageContext,
copyAsTemplate, copyAsTemplate,
createFromTemplate, createFromTemplate,
@ -90,7 +99,7 @@ final class SEBExamConfigCreationPopup {
}; };
} }
private static boolean doCreate( private boolean doCreate(
final PageService pageService, final PageService pageService,
final PageContext pageContext, final PageContext pageContext,
final boolean copyAsTemplate, final boolean copyAsTemplate,
@ -130,7 +139,7 @@ final class SEBExamConfigCreationPopup {
return true; return true;
} }
private static final class CreationFormContext implements ModalInputDialogComposer<FormHandle<ConfigCreationInfo>> { private final class CreationFormContext implements ModalInputDialogComposer<FormHandle<ConfigCreationInfo>> {
private final PageService pageService; private final PageService pageService;
private final PageContext pageContext; private final PageContext pageContext;
@ -188,7 +197,5 @@ final class SEBExamConfigCreationPopup {
return () -> formHandle; return () -> formHandle;
} }
} }
} }

View file

@ -103,19 +103,24 @@ public class SEBExamConfigForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final SEBExamConfigCreationPopup sebExamConfigCreationPopup;
private final SEBExamConfigImportPopup sebExamConfigImportPopup;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final DownloadService downloadService; private final DownloadService downloadService;
private final String downloadFileName; private final String downloadFileName;
protected SEBExamConfigForm( protected SEBExamConfigForm(
final PageService pageService, final PageService pageService,
final CurrentUser currentUser, final SEBExamConfigCreationPopup sebExamConfigCreationPopup,
final SEBExamConfigImportPopup sebExamConfigImportPopup,
final DownloadService downloadService, final DownloadService downloadService,
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) { @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
this.pageService = pageService; this.pageService = pageService;
this.restService = pageService.getRestService(); this.restService = pageService.getRestService();
this.currentUser = currentUser; this.sebExamConfigCreationPopup = sebExamConfigCreationPopup;
this.sebExamConfigImportPopup = sebExamConfigImportPopup;
this.currentUser = pageService.getCurrentUser();
this.downloadService = downloadService; this.downloadService = downloadService;
this.downloadFileName = downloadFileName; this.downloadFileName = downloadFileName;
} }
@ -228,8 +233,7 @@ public class SEBExamConfigForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SEBExamConfigCreationPopup.configCreationFunction( .withExec(this.sebExamConfigCreationPopup.configCreationFunction(
this.pageService,
actionContext actionContext
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withAttribute( .withAttribute(
@ -243,8 +247,7 @@ public class SEBExamConfigForm implements TemplateComposer {
.newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SEBExamConfigCreationPopup.configCreationFunction( .withExec(this.sebExamConfigCreationPopup.configCreationFunction(
this.pageService,
pageContext.withAttribute( pageContext.withAttribute(
PageContext.AttributeKeys.COPY_AS_TEMPLATE, PageContext.AttributeKeys.COPY_AS_TEMPLATE,
Constants.TRUE_STRING))) Constants.TRUE_STRING)))
@ -272,7 +275,7 @@ public class SEBExamConfigForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SEBExamConfigImportPopup.importFunction(this.pageService, false)) .withExec(this.sebExamConfigImportPopup.importFunction(false))
.noEventPropagation() .noEventPropagation()
.publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam) .publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam)

View file

@ -19,6 +19,8 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Control;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; 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.Result;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; 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.service.remote.webservice.api.seb.examconfig.ImportNewExamConfig;
import ch.ethz.seb.sebserver.gui.widget.FileUploadSelection; 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 static final Logger log = LoggerFactory.getLogger(SEBExamConfigImportPopup.class);
private final static PageMessageException MISSING_PASSWORD = new PageMessageException( private final static PageMessageException MISSING_PASSWORD = new PageMessageException(
new LocTextKey("sebserver.examconfig.action.import.missing-password")); new LocTextKey("sebserver.examconfig.action.import.missing-password"));
static Function<PageAction, PageAction> importFunction( private final PageService pageService;
final PageService pageService,
final boolean newConfig) {
protected SEBExamConfigImportPopup(final PageService pageService) {
this.pageService = pageService;
}
public Function<PageAction, PageAction> importFunction(final boolean newConfig) {
return action -> { return action -> {
final ModalInputDialog<FormHandle<ConfigurationNode>> dialog = final ModalInputDialog<FormHandle<ConfigurationNode>> dialog =
new ModalInputDialog<FormHandle<ConfigurationNode>>( new ModalInputDialog<FormHandle<ConfigurationNode>>(
action.pageContext().getParent().getShell(), action.pageContext().getParent().getShell(),
pageService.getWidgetFactory()) this.pageService.getWidgetFactory())
.setLargeDialogWidth(); .setLargeDialogWidth();
final ImportFormContext importFormContext = new ImportFormContext( final ImportFormContext importFormContext = new ImportFormContext(
pageService, this.pageService,
action.pageContext(), action.pageContext(),
newConfig); newConfig);
dialog.open( dialog.open(
SEBExamConfigForm.FORM_IMPORT_TEXT_KEY, SEBExamConfigForm.FORM_IMPORT_TEXT_KEY,
(Predicate<FormHandle<ConfigurationNode>>) formHandle -> doImport( (Predicate<FormHandle<ConfigurationNode>>) formHandle -> doImport(
pageService,
formHandle, formHandle,
newConfig), newConfig),
importFormContext::cancelUpload, importFormContext::cancelUpload,
@ -86,8 +94,7 @@ final class SEBExamConfigImportPopup {
}; };
} }
private static boolean doImport( private boolean doImport(
final PageService pageService,
final FormHandle<ConfigurationNode> formHandle, final FormHandle<ConfigurationNode> formHandle,
final boolean newConfig) { final boolean newConfig) {
@ -104,14 +111,14 @@ final class SEBExamConfigImportPopup {
if (StringUtils.isBlank(fieldValue)) { if (StringUtils.isBlank(fieldValue)) {
form.setFieldError( form.setFieldError(
Domain.CONFIGURATION_NODE.ATTR_NAME, Domain.CONFIGURATION_NODE.ATTR_NAME,
pageService this.pageService
.getI18nSupport() .getI18nSupport()
.getText(new LocTextKey("sebserver.form.validation.fieldError.notNull"))); .getText(new LocTextKey("sebserver.form.validation.fieldError.notNull")));
return false; return false;
} else if (fieldValue.length() < 3 || fieldValue.length() > 255) { } else if (fieldValue.length() < 3 || fieldValue.length() > 255) {
form.setFieldError( form.setFieldError(
Domain.CONFIGURATION_NODE.ATTR_NAME, Domain.CONFIGURATION_NODE.ATTR_NAME,
pageService this.pageService
.getI18nSupport() .getI18nSupport()
.getText(new LocTextKey("sebserver.form.validation.fieldError.size", .getText(new LocTextKey("sebserver.form.validation.fieldError.size",
null, null,
@ -123,7 +130,7 @@ final class SEBExamConfigImportPopup {
} else { } else {
// check if name already exists // check if name already exists
try { try {
if (pageService.getRestService() if (this.pageService.getRestService()
.getBuilder(GetExamConfigNodeNames.class) .getBuilder(GetExamConfigNodeNames.class)
.call() .call()
.getOrThrow() .getOrThrow()
@ -134,7 +141,7 @@ final class SEBExamConfigImportPopup {
form.setFieldError( form.setFieldError(
Domain.CONFIGURATION_NODE.ATTR_NAME, Domain.CONFIGURATION_NODE.ATTR_NAME,
pageService this.pageService
.getI18nSupport() .getI18nSupport()
.getText(new LocTextKey( .getText(new LocTextKey(
"sebserver.form.validation.fieldError.name.notunique"))); "sebserver.form.validation.fieldError.name.notunique")));
@ -151,9 +158,9 @@ final class SEBExamConfigImportPopup {
final InputStream inputStream = fileUpload.getInputStream(); final InputStream inputStream = fileUpload.getInputStream();
if (inputStream != null) { if (inputStream != null) {
final RestCall<Configuration>.RestCallBuilder restCall = (newConfig) final RestCall<Configuration>.RestCallBuilder restCall = (newConfig)
? pageService.getRestService() ? this.pageService.getRestService()
.getBuilder(ImportNewExamConfig.class) .getBuilder(ImportNewExamConfig.class)
: pageService.getRestService() : this.pageService.getRestService()
.getBuilder(ImportExamConfigOnExistingConfig.class); .getBuilder(ImportExamConfigOnExistingConfig.class);
restCall restCall
@ -184,11 +191,11 @@ final class SEBExamConfigImportPopup {
context.publishInfo(SEBExamConfigForm.FORM_IMPORT_CONFIRM_TEXT_KEY); context.publishInfo(SEBExamConfigForm.FORM_IMPORT_CONFIRM_TEXT_KEY);
if (newConfig) { if (newConfig) {
final PageAction action = pageService.pageActionBuilder(context) final PageAction action = this.pageService.pageActionBuilder(context)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG)
.create(); .create();
pageService.firePageEvent( this.pageService.firePageEvent(
new ActionEvent(action), new ActionEvent(action),
action.pageContext()); action.pageContext());
} }
@ -233,7 +240,7 @@ final class SEBExamConfigImportPopup {
} }
} }
private static final class ImportFormContext implements ModalInputDialogComposer<FormHandle<ConfigurationNode>> { private final class ImportFormContext implements ModalInputDialogComposer<FormHandle<ConfigurationNode>> {
private final PageService pageService; private final PageService pageService;
private final PageContext pageContext; private final PageContext pageContext;

View file

@ -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.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; 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.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.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;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; 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 TableFilterAttribute statusFilter;
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final SEBExamConfigImportPopup sebExamConfigImportPopup;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ResourceService resourceService; private final ResourceService resourceService;
private final int pageSize; private final int pageSize;
protected SEBExamConfigList( protected SEBExamConfigList(
final PageService pageService, final PageService pageService,
final RestService restService, final SEBExamConfigImportPopup sebExamConfigImportPopup,
final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.sebExamConfigImportPopup = sebExamConfigImportPopup;
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
@ -109,7 +107,7 @@ public class SEBExamConfigList implements TemplateComposer {
// exam configuration table // exam configuration table
final EntityTable<ConfigurationNode> configTable = final EntityTable<ConfigurationNode> configTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) this.pageService.entityTableBuilder(GetExamConfigNodePage.class)
.withStaticFilter( .withStaticFilter(
Domain.CONFIGURATION_NODE.ATTR_TYPE, Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name()) ConfigurationType.EXAM_CONFIG.name())
@ -172,7 +170,7 @@ public class SEBExamConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG)
.withSelect( .withSelect(
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
SEBExamConfigImportPopup.importFunction(this.pageService, true), this.sebExamConfigImportPopup.importFunction(true),
EMPTY_SELECTION_TEXT_KEY) EMPTY_SELECTION_TEXT_KEY)
.noEventPropagation() .noEventPropagation()
.publishIf(examConfigGrant::im); .publishIf(examConfigGrant::im);

View file

@ -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.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.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.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.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;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -73,18 +73,19 @@ public class SEBSettingsForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final SEBExamConfigCreationPopup sebExamConfigCreationPopup;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService; private final ExamConfigurationService examConfigurationService;
protected SEBSettingsForm( protected SEBSettingsForm(
final PageService pageService, final PageService pageService,
final RestService restService, final SEBExamConfigCreationPopup sebExamConfigCreationPopup,
final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.sebExamConfigCreationPopup = sebExamConfigCreationPopup;
this.currentUser = pageService.getCurrentUser();
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;
} }
@ -192,8 +193,7 @@ public class SEBSettingsForm implements TemplateComposer {
.newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SEBExamConfigCreationPopup.configCreationFunction( .withExec(this.sebExamConfigCreationPopup.configCreationFunction(
this.pageService,
pageContext pageContext
.withAttribute( .withAttribute(
PageContext.AttributeKeys.COPY_AS_TEMPLATE, PageContext.AttributeKeys.COPY_AS_TEMPLATE,

View file

@ -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 * If the current user is the owner of the User-Account the password is required and must
* match the users current password. * match the users current password.
* If the current user is an administrator that has to reset another users password the * 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 { public class UserAccountChangePasswordForm implements TemplateComposer {
private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title"; 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 CurrentUser currentUser;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
protected UserAccountChangePasswordForm( protected UserAccountChangePasswordForm(final PageService pageService) {
final PageService pageService,
final RestService restService,
final CurrentUser currentUser) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = pageService.getRestService();
this.currentUser = currentUser; this.currentUser = pageService.getCurrentUser();
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
} }

View file

@ -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<PageAction, PageAction> deleteWizardFunction(final PageContext pageContext) {
return action -> {
final ModelInputWizard<PageContext> wizard =
new ModelInputWizard<PageContext>(
action.pageContext().getParent().getShell(),
this.pageService.getWidgetFactory())
.setLargeDialogWidth();
final String page1Id = "DELETE_PAGE";
final String page2Id = "REPORT_PAGE";
final Predicate<PageContext> callback = pc -> doDelete(this.pageService, pc);
final BiFunction<PageContext, Composite, Supplier<PageContext>> composePage1 =
(formHandle, content) -> composeDeleteDialog(content, pageContext);
final BiFunction<PageContext, Composite, Supplier<PageContext>> composePage2 =
(formHandle, content) -> composeReportDialog(content, pageContext);
final WizardPage<PageContext> page1 = new WizardPage<>(
page1Id,
true,
composePage1,
new WizardAction<>(ACTION_DELETE, callback),
new WizardAction<>(ACTION_REPORT, page2Id));
final WizardPage<PageContext> page2 = new WizardPage<>(
page2Id,
false,
composePage2,
new WizardAction<>(ACTION_DELETE, callback));
wizard.open(FORM_TITLE, Utils.EMPTY_EXECUTION, page1, page2);
return action;
};
}
private boolean doDelete(
final PageService pageService,
final PageContext pageContext) {
final boolean withConfigs = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_CONFIGS));
final boolean withExams = BooleanUtils.toBoolean(pageContext.getAttribute(ARG_WITH_EXAMS));
return true;
}
private Supplier<PageContext> 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<PageContext> 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<Set<EntityDependency>>.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<ConfigurationNode> configTable =
// this.pageService.entityTableBuilder(GetUserDependency.class)
// .
final Set<EntityDependency> dependencies = restCallBuilder.call().getOrThrow();
// TODO get dependencies in case of selection and show all in a list (type / name)
return () -> pageContext;
}
}

View file

@ -86,15 +86,17 @@ public class UserAccountForm implements TemplateComposer {
private final PageService pageService; private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
private final UserAccountDeletePopup userAccountDeletePopup;
private final boolean multilingual; private final boolean multilingual;
protected UserAccountForm( protected UserAccountForm(
final PageService pageService, final PageService pageService,
final ResourceService resourceService, final UserAccountDeletePopup userAccountDeletePopup,
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) { @Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.userAccountDeletePopup = userAccountDeletePopup;
this.multilingual = BooleanUtils.toBoolean(multilingual); this.multilingual = BooleanUtils.toBoolean(multilingual);
} }
@ -266,6 +268,11 @@ public class UserAccountForm implements TemplateComposer {
.withSimpleRestCall(restService, ActivateUserAccount.class) .withSimpleRestCall(restService, ActivateUserAccount.class)
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive()) .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) .newAction(ActionDefinition.USER_ACCOUNT_SAVE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost() .withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost()
@ -289,4 +296,5 @@ public class UserAccountForm implements TemplateComposer {
.withExec(this.pageService.backToCurrentFunction()) .withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !readonly); .publishIf(() -> !readonly);
} }
} }

View file

@ -96,12 +96,11 @@ public class UserAccountList implements TemplateComposer {
protected UserAccountList( protected UserAccountList(
final PageService pageService, final PageService pageService,
final ResourceService resourceService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize,
@Value("${sebserver.gui.multilingual:false}") final Boolean ml) { @Value("${sebserver.gui.multilingual:false}") final Boolean ml) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.multilingual = BooleanUtils.isTrue(ml); this.multilingual = BooleanUtils.isTrue(ml);

View file

@ -130,6 +130,11 @@ public enum ActionDefinition {
ImageIcon.SWITCH, ImageIcon.SWITCH,
PageStateDefinitionImpl.USER_ACCOUNT_LIST, PageStateDefinitionImpl.USER_ACCOUNT_LIST,
ActionCategory.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( USER_ACCOUNT_CHANGE_PASSWORD(
new LocTextKey("sebserver.useraccount.action.change.password"), new LocTextKey("sebserver.useraccount.action.change.password"),

View file

@ -280,6 +280,15 @@ public interface PageService {
* @return a FormBuilder instance for the given PageContext and with number of rows */ * @return a FormBuilder instance for the given PageContext and with number of rows */
FormBuilder formBuilder(PageContext pageContext, int 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 <T> the type of the Entity of the table
* @return TableBuilder of specified type */
default <T extends Entity> TableBuilder<T> entityTableBuilder(final Class<? extends RestCall<Page<T>>> apiCall) {
return entityTableBuilder(this.getRestService().getRestCall(apiCall));
}
/** Get an new TableBuilder for specified page based RestCall. /** Get an new TableBuilder for specified page based RestCall.
* *
* @param apiCall the SEB Server API RestCall that feeds the table with data * @param apiCall the SEB Server API RestCall that feeds the table with data

View file

@ -38,11 +38,11 @@ public class ModalInputDialog<T> extends Dialog {
public static final int LARGE_DIALOG_WIDTH = 600; public static final int LARGE_DIALOG_WIDTH = 600;
public static final int VERY_LARGE_DIALOG_WIDTH = 800; 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"); 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"); 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"); new LocTextKey("sebserver.overall.action.close");
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;

View file

@ -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<T> 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<T> setDialogWidth(final int dialogWidth) {
this.dialogWidth = dialogWidth;
return this;
}
public ModelInputWizard<T> setLargeDialogWidth() {
this.dialogWidth = ModalInputDialog.LARGE_DIALOG_WIDTH;
return this;
}
public ModelInputWizard<T> setVeryLargeDialogWidth() {
this.dialogWidth = ModalInputDialog.VERY_LARGE_DIALOG_WIDTH;
return this;
}
public ModelInputWizard<T> setDialogHeight(final int dialogHeight) {
this.dialogHeight = dialogHeight;
return this;
}
public ModelInputWizard<T> setButtonWidth(final int buttonWidth) {
this.buttonWidth = buttonWidth;
return this;
}
@SafeVarargs
public final void open(
final LocTextKey title,
final Runnable cancelCallback,
final WizardPage<T>... 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<WizardPage<T>> 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<WizardPage<T>> pages,
final T valueFromPrevPage,
final Composite contentComp,
final Composite actionsComp) {
final Optional<WizardPage<T>> 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<T> page = newPage.get();
PageService.clearComposite(contentComp);
PageService.clearComposite(actionsComp);
final Supplier<T> valueSupplier = page.contentCompose.apply(valueFromPrevPage, contentComp);
if (page.actions != null) {
for (final WizardAction<T> 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<T> {
public final String id;
public final boolean isStart;
public final BiFunction<T, Composite, Supplier<T>> contentCompose;
public final List<WizardAction<T>> actions;
@SafeVarargs
public WizardPage(
final String id,
final boolean isStart,
final BiFunction<T, Composite, Supplier<T>> contentCompose,
final WizardAction<T>... actions) {
this.id = id;
this.isStart = isStart;
this.contentCompose = contentCompose;
this.actions = Utils.asImmutableList(actions);
}
}
public static final class WizardAction<T> {
public final LocTextKey name;
public final String toPage;
public final Predicate<T> 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<T> callback) {
this.name = name;
this.toPage = null;
this.callback = callback;
}
}
}

View file

@ -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.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetExamDependencies extends RestCall<Set<EntityKey>> { public class GetExamDependencies extends RestCall<Set<EntityDependency>> {
public GetExamDependencies() { public GetExamDependencies() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_DEPENDENCIES, CallType.GET_DEPENDENCIES,
EntityType.EXAM, EntityType.EXAM,
new TypeReference<Set<EntityKey>>() { new TypeReference<Set<EntityDependency>>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -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.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetInstitutionDependency extends RestCall<Set<EntityKey>> { public class GetInstitutionDependency extends RestCall<Set<EntityDependency>> {
public GetInstitutionDependency() { public GetInstitutionDependency() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_DEPENDENCIES, CallType.GET_DEPENDENCIES,
EntityType.INSTITUTION, EntityType.INSTITUTION,
new TypeReference<Set<EntityKey>>() { new TypeReference<Set<EntityDependency>>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -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.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetLmsSetupDependencies extends RestCall<Set<EntityKey>> { public class GetLmsSetupDependencies extends RestCall<Set<EntityDependency>> {
public GetLmsSetupDependencies() { public GetLmsSetupDependencies() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_DEPENDENCIES, CallType.GET_DEPENDENCIES,
EntityType.LMS_SETUP, EntityType.LMS_SETUP,
new TypeReference<Set<EntityKey>>() { new TypeReference<Set<EntityDependency>>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -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.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetUserDependency extends RestCall<Set<EntityKey>> { public class GetUserDependency extends RestCall<Set<EntityDependency>> {
public GetUserDependency() { public GetUserDependency() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_DEPENDENCIES, CallType.GET_DEPENDENCIES,
EntityType.USER, EntityType.USER,
new TypeReference<Set<EntityKey>>() { new TypeReference<Set<EntityDependency>>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -80,8 +80,8 @@ public class EntityTable<ROW extends Entity> {
final PageService pageService; final PageService pageService;
final WidgetFactory widgetFactory; final WidgetFactory widgetFactory;
final RestCall<Page<ROW>> restCall; final PageSupplier<ROW> pageSupplier;
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter; final Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> pageSupplierAdapter;
final I18nSupport i18nSupport; final I18nSupport i18nSupport;
final PageContext pageContext; final PageContext pageContext;
@ -109,7 +109,7 @@ public class EntityTable<ROW extends Entity> {
final int type, final int type,
final PageContext pageContext, final PageContext pageContext,
final RestCall<Page<ROW>> restCall, final RestCall<Page<ROW>> restCall,
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter, final Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> pageSupplierAdapter,
final PageService pageService, final PageService pageService,
final List<ColumnDefinition<ROW>> columns, final List<ColumnDefinition<ROW>> columns,
final int pageSize, final int pageSize,
@ -132,8 +132,8 @@ public class EntityTable<ROW extends Entity> {
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
this.pageContext = pageContext; this.pageContext = pageContext;
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.restCall = restCall; this.pageSupplier = new RestCallPageSupplier<>(restCall);
this.restCallAdapter = (restCallAdapter != null) ? restCallAdapter : Function.identity(); this.pageSupplierAdapter = (pageSupplierAdapter != null) ? pageSupplierAdapter : Function.identity();
this.columns = Utils.immutableListOf(columns); this.columns = Utils.immutableListOf(columns);
this.emptyMessage = emptyMessage; this.emptyMessage = emptyMessage;
this.hideNavigation = hideNavigation; this.hideNavigation = hideNavigation;
@ -233,8 +233,8 @@ public class EntityTable<ROW extends Entity> {
} }
public EntityType getEntityType() { public EntityType getEntityType() {
if (this.restCall != null) { if (this.pageSupplier != null) {
return this.restCall.getEntityType(); return this.pageSupplier.getEntityType();
} }
return null; return null;
@ -471,13 +471,13 @@ public class EntityTable<ROW extends Entity> {
this.table.removeAll(); this.table.removeAll();
// get page data and create rows // get page data and create rows
this.restCall.newBuilder() this.pageSupplier.newBuilder()
.withPaging(pageNumber, pageSize) .withPaging(pageNumber, pageSize)
.withSorting(sortColumn, sortOrder) .withSorting(sortColumn, sortOrder)
.withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null) .withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null)
.withQueryParams(this.staticQueryParams) .withQueryParams(this.staticQueryParams)
.apply(this.restCallAdapter) .apply(this.pageSupplierAdapter)
.call() .getPage()
.map(this::createTableRowsFromPage) .map(this::createTableRowsFromPage)
.map(this.navigator::update) .map(this.navigator::update)
.onError(this.pageContext::notifyUnexpectedError); .onError(this.pageContext::notifyUnexpectedError);

View file

@ -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<T> {
EntityType getEntityType();
Builder<T> newBuilder();
public interface Builder<T> {
public Builder<T> withPaging(final int pageNumber, final int pageSize);
public Builder<T> withSorting(final String column, final PageSortOrder order);
public Builder<T> withQueryParams(final MultiValueMap<String, String> params);
public Builder<T> withQueryParam(String name, String value);
public Builder<T> withURIVariable(String name, String id);
public Builder<T> apply(final Function<Builder<T>, Builder<T>> f);
public Result<Page<T>> getPage();
}
}

View file

@ -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<T> implements PageSupplier<T> {
private final RestCall<Page<T>> restCall;
protected RestCallPageSupplier(final RestCall<Page<T>> restCall) {
this.restCall = restCall;
}
@Override
public EntityType getEntityType() {
return this.restCall.getEntityType();
}
@Override
public Builder<T> newBuilder() {
final RestCall<Page<T>>.RestCallBuilder restCallBuilder = this.restCall.newBuilder();
return new Builder<>() {
@Override
public Builder<T> withPaging(final int pageNumber, final int pageSize) {
restCallBuilder.withPaging(pageNumber, pageSize);
return this;
}
@Override
public Builder<T> withSorting(final String column, final PageSortOrder order) {
restCallBuilder.withSorting(column, order);
return this;
}
@Override
public Builder<T> withQueryParams(final MultiValueMap<String, String> params) {
restCallBuilder.withQueryParams(params);
return this;
}
@Override
public Builder<T> withQueryParam(final String name, final String value) {
restCallBuilder.withQueryParam(name, value);
return this;
}
@Override
public Builder<T> withURIVariable(final String name, final String id) {
restCallBuilder.withURIVariable(name, id);
return this;
}
@Override
public Builder<T> apply(final Function<Builder<T>, Builder<T>> f) {
return f.apply(this);
}
@Override
public Result<Page<T>> getPage() {
return restCallBuilder.call();
}
};
}
}

View file

@ -42,7 +42,7 @@ public class TableBuilder<ROW extends Entity> {
private int pageSize = -1; private int pageSize = -1;
private int type = SWT.NONE; private int type = SWT.NONE;
private boolean hideNavigation = false; private boolean hideNavigation = false;
private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter; private Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> restCallAdapter;
private BiConsumer<TableItem, ROW> rowDecorator; private BiConsumer<TableItem, ROW> rowDecorator;
private Consumer<Set<ROW>> selectionListener; private Consumer<Set<ROW>> selectionListener;
private boolean markupEnabled = false; private boolean markupEnabled = false;
@ -94,7 +94,7 @@ public class TableBuilder<ROW extends Entity> {
} }
public TableBuilder<ROW> withRestCallAdapter( public TableBuilder<ROW> withRestCallAdapter(
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> adapter) { final Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> adapter) {
this.restCallAdapter = adapter; this.restCallAdapter = adapter;
return this; return this;

View file

@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
@ -42,7 +43,7 @@ public interface BulkActionSupportDAO<T extends Entity> {
* @param bulkAction the BulkAction to get keys of dependencies for the concrete type of this 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 * @return Collection of Result. Each Result refers to the EntityKey of processed entity or to an error if
* happened */ * happened */
Set<EntityKey> getDependencies(BulkAction bulkAction); Set<EntityDependency> getDependencies(BulkAction bulkAction);
/** This processed a given BulkAction for all entities of the concrete type of this BulkActionSupportDAO /** This processed a given BulkAction for all entities of the concrete type of this BulkActionSupportDAO
* that are defined by this given BulkAction. * that are defined by this given BulkAction.
@ -104,16 +105,16 @@ public interface BulkActionSupportDAO<T extends Entity> {
/** Get dependency keys of all source entities of a given BulkAction /** Get dependency keys of all source entities of a given BulkAction
* This method simply goes through all source EntityKeys of the 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 * into one Set of all dependency keys for all source keys
* *
* *
* @param bulkAction The BulkAction that defines the 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 * @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 */ * @return Set of EntityDependency instances that define all entities that depends on the given bulk action */
default Set<EntityKey> getDependencies( default Set<EntityDependency> getDependencies(
final BulkAction bulkAction, final BulkAction bulkAction,
final Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction) { final Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction) {
return bulkAction.sources return bulkAction.sources
.stream() .stream()

View file

@ -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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType; import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType;
import ch.ethz.seb.sebserver.gbl.util.Result; 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 */ * Null means all dependencies are included (ignore) and empty means no dependencies are included */
public final EnumSet<EntityType> includeDependencies; public final EnumSet<EntityType> includeDependencies;
/** A Set of EntityKey containing collected depending entities during dependency collection and processing phase */ /** A Set of EntityKey containing collected depending entities during dependency collection and processing phase */
final Set<EntityKey> dependencies; final Set<EntityDependency> dependencies;
/** A Set of EntityKey containing collected bulk action processing results during processing phase */ /** A Set of EntityKey containing collected bulk action processing results during processing phase */
final Set<Result<EntityKey>> result; final Set<Result<EntityKey>> result;
/** Indicates if this BulkAction has already been processed and is not valid anymore */ /** 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); return this.includeDependencies == null || this.includeDependencies.contains(type);
} }
public Set<EntityKey> getDependencies() { public Set<EntityDependency> getDependencies() {
return Collections.unmodifiableSet(this.dependencies); return Collections.unmodifiableSet(this.dependencies);
} }
@ -93,7 +94,8 @@ public final class BulkAction {
if (!this.dependencies.isEmpty()) { if (!this.dependencies.isEmpty()) {
return Collections.unmodifiableSet(new HashSet<>(this.dependencies return Collections.unmodifiableSet(new HashSet<>(this.dependencies
.stream() .stream()
.filter(key -> key.entityType == type) .filter(dependency -> dependency.self.entityType == type)
.map(dependency -> dependency.self)
.collect(Collectors.toList()))); .collect(Collectors.toList())));
} }

View file

@ -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.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry;
@ -184,13 +185,13 @@ public class BulkActionServiceImpl implements BulkActionService {
return; return;
} }
for (final EntityKey key : action.dependencies) { for (final EntityDependency dependency : action.dependencies) {
this.userActivityLogDAO.log( this.userActivityLogDAO.log(
activityType, activityType,
key.entityType, dependency.self.entityType,
key.modelId, dependency.self.modelId,
"Bulk Action - Dependency : " + toLogMessage(key)); "Bulk Action - Dependency : " + toLogMessage(dependency));
} }
for (final EntityKey key : action.sources) { for (final EntityKey key : action.sources) {
@ -214,6 +215,18 @@ public class BulkActionServiceImpl implements BulkActionService {
return entityAsString; 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<BulkActionSupportDAO<?>> getDependencySupporter(final BulkAction action) { private List<BulkActionSupportDAO<?>> getDependencySupporter(final BulkAction action) {
switch (action.type) { switch (action.type) {
case ACTIVATE: case ACTIVATE:

View file

@ -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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
@ -181,7 +182,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
} }
@Override @Override
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// only for deletion // only for deletion
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
return Collections.emptySet(); return Collections.emptySet();
@ -192,7 +193,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
} }
// define the select function in case of source type // define the select function in case of source type
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction; Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction;
switch (bulkAction.sourceType) { switch (bulkAction.sourceType) {
case INSTITUTION: case INSTITUTION:
selectionFunction = this::allIdsOfInstitution; selectionFunction = this::allIdsOfInstitution;
@ -317,20 +318,24 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
}); });
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample()
.where( .where(
ClientConnectionRecordDynamicSqlSupport.institutionId, ClientConnectionRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.parseLong(institutionKey.modelId))) isEqualTo(Long.parseLong(institutionKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { private Result<Collection<EntityDependency>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample()
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
.on( .on(
ExamRecordDynamicSqlSupport.id, ExamRecordDynamicSqlSupport.id,
@ -341,12 +346,16 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) { private Result<Collection<EntityDependency>> allIdsOfUser(final EntityKey userKey) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample()
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
.on( .on(
ExamRecordDynamicSqlSupport.id, ExamRecordDynamicSqlSupport.id,
@ -357,19 +366,27 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfExam(final EntityKey examKey) { private Result<Collection<EntityDependency>> allIdsOfExam(final EntityKey examKey) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByExample()
.where( .where(
ClientConnectionRecordDynamicSqlSupport.examId, ClientConnectionRecordDynamicSqlSupport.examId,
isEqualTo(Long.parseLong(examKey.modelId))) isEqualTo(Long.parseLong(examKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException; import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigCreationInfo; 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;
@ -134,14 +135,14 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// only if included // only if included
if (!bulkAction.includesDependencyType(EntityType.CONFIGURATION_NODE)) { if (!bulkAction.includesDependencyType(EntityType.CONFIGURATION_NODE)) {
return Collections.emptySet(); return Collections.emptySet();
} }
// define the select function in case of source type // define the select function in case of source type
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction = Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction =
key -> Result.of(Collections.emptyList()); key -> Result.of(Collections.emptyList());
if (bulkAction.sourceType == EntityType.INSTITUTION) { if (bulkAction.sourceType == EntityType.INSTITUTION) {
@ -254,27 +255,35 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
}); });
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectByExample()
.where( .where(
ConfigurationNodeRecordDynamicSqlSupport.institutionId, ConfigurationNodeRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId))) isEqualTo(Long.valueOf(institutionKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) { private Result<Collection<EntityDependency>> allIdsOfUser(final EntityKey userKey) {
return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectByExample()
.where( .where(
ConfigurationNodeRecordDynamicSqlSupport.owner, ConfigurationNodeRecordDynamicSqlSupport.owner,
isEqualTo(userKey.modelId)) isEqualTo(userKey.modelId))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
@ -280,7 +281,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// only deletion here // only deletion here
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
return Collections.emptySet(); return Collections.emptySet();
@ -291,7 +292,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
} }
// define the select function in case of source type // define the select function in case of source type
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction; Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction;
switch (bulkAction.sourceType) { switch (bulkAction.sourceType) {
case INSTITUTION: case INSTITUTION:
selectionFunction = this::allIdsOfInstitution; selectionFunction = this::allIdsOfInstitution;
@ -361,6 +362,14 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
}); });
} }
private Result<Collection<ExamConfigurationMap>> toDomainModel(
final Collection<ExamConfigurationMapRecord> records) {
return Result.tryCatch(() -> records
.stream()
.map(model -> this.toDomainModel(model).getOrThrow())
.collect(Collectors.toList()));
}
private Result<ExamConfigurationMap> toDomainModel(final ExamConfigurationMapRecord record) { private Result<ExamConfigurationMap> toDomainModel(final ExamConfigurationMapRecord record) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
@ -420,81 +429,93 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
}); });
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where( this.examConfigurationMapRecordMapper.selectByExample()
ExamConfigurationMapRecordDynamicSqlSupport.institutionId, .where(
isEqualTo(Long.valueOf(institutionKey.modelId))) ExamConfigurationMapRecordDynamicSqlSupport.institutionId,
.build() isEqualTo(Long.valueOf(institutionKey.modelId)))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) institutionKey));
.collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) { private Result<Collection<EntityDependency>> allIdsOfUser(final EntityKey userKey) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final List<Long> examsIds = this.examRecordMapper.selectByExample() final List<Long> examsIds = this.examRecordMapper.selectIdsByExample()
.where( .where(
ExamRecordDynamicSqlSupport.owner, ExamRecordDynamicSqlSupport.owner,
isEqualTo(userKey.modelId)) isEqualTo(userKey.modelId))
.build() .build()
.execute() .execute();
.stream()
.map(r -> r.getId())
.collect(Collectors.toList());
return this.examConfigurationMapRecordMapper.selectIdsByExample() return toDependencies(
.where( this.examConfigurationMapRecordMapper.selectByExample()
ExamConfigurationMapRecordDynamicSqlSupport.examId, .where(
isIn(examsIds)) ExamConfigurationMapRecordDynamicSqlSupport.examId,
.build() isIn(examsIds))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) userKey);
.collect(Collectors.toList());
}); });
} }
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { private Result<Collection<EntityDependency>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) this.examConfigurationMapRecordMapper.selectByExample()
.on( .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
ExamRecordDynamicSqlSupport.id, .on(
equalTo(ExamConfigurationMapRecordDynamicSqlSupport.examId)) ExamRecordDynamicSqlSupport.id,
equalTo(ExamConfigurationMapRecordDynamicSqlSupport.examId))
.where( .where(
ExamRecordDynamicSqlSupport.lmsSetupId, ExamRecordDynamicSqlSupport.lmsSetupId,
isEqualTo(Long.valueOf(lmsSetupKey.modelId))) isEqualTo(Long.valueOf(lmsSetupKey.modelId)))
.build() .build()
.execute() .execute(),
.stream() lmsSetupKey));
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP))
.collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfExam(final EntityKey examKey) { private Result<Collection<EntityDependency>> allIdsOfExam(final EntityKey examKey) {
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where( this.examConfigurationMapRecordMapper.selectByExample()
ExamConfigurationMapRecordDynamicSqlSupport.examId, .where(
isEqualTo(Long.valueOf(examKey.modelId))) ExamConfigurationMapRecordDynamicSqlSupport.examId,
.build() isEqualTo(Long.valueOf(examKey.modelId)))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) examKey));
.collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfConfig(final EntityKey configKey) { private Result<Collection<EntityDependency>> allIdsOfConfig(final EntityKey configKey) {
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where( this.examConfigurationMapRecordMapper.selectByExample()
ExamConfigurationMapRecordDynamicSqlSupport.configurationNodeId, .where(
isEqualTo(Long.valueOf(configKey.modelId))) ExamConfigurationMapRecordDynamicSqlSupport.configurationNodeId,
.build() isEqualTo(Long.valueOf(configKey.modelId)))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP)) configKey));
.collect(Collectors.toList())); }
private Collection<EntityDependency> toDependencies(
final List<ExamConfigurationMapRecord> 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) { private String getEncryptionPassword(final ExamConfigurationMap examConfigurationMap) {

View file

@ -32,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus; import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
@ -587,14 +588,14 @@ public class ExamDAOImpl implements ExamDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// only if included // only if included
if (!bulkAction.includesDependencyType(EntityType.EXAM)) { if (!bulkAction.includesDependencyType(EntityType.EXAM)) {
return Collections.emptySet(); return Collections.emptySet();
} }
// define the select function in case of source type // define the select function in case of source type
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction; Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction;
switch (bulkAction.sourceType) { switch (bulkAction.sourceType) {
case INSTITUTION: case INSTITUTION:
selectionFunction = this::allIdsOfInstitution; selectionFunction = this::allIdsOfInstitution;
@ -636,37 +637,34 @@ public class ExamDAOImpl implements ExamDAO {
.execute()); .execute());
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where(ExamRecordDynamicSqlSupport.institutionId, this.examRecordMapper.selectByExample()
isEqualTo(Long.valueOf(institutionKey.modelId))) .where(ExamRecordDynamicSqlSupport.institutionId,
.build() isEqualTo(Long.valueOf(institutionKey.modelId)))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM)) institutionKey));
.collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { private Result<Collection<EntityDependency>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where(ExamRecordDynamicSqlSupport.lmsSetupId, this.examRecordMapper.selectByExample()
isEqualTo(Long.valueOf(lmsSetupKey.modelId))) .where(ExamRecordDynamicSqlSupport.lmsSetupId,
.build() isEqualTo(Long.valueOf(lmsSetupKey.modelId)))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM)) lmsSetupKey));
.collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) { private Result<Collection<EntityDependency>> allIdsOfUser(final EntityKey userKey) {
return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample() return Result.tryCatch(() -> toDependencies(
.where(ExamRecordDynamicSqlSupport.owner, this.examRecordMapper.selectByExample()
isEqualTo(userKey.modelId)) .where(ExamRecordDynamicSqlSupport.owner,
.build() isEqualTo(userKey.modelId))
.execute() .build()
.stream() .execute(),
.map(id -> new EntityKey(id, EntityType.EXAM)) userKey));
.collect(Collectors.toList()));
} }
private Result<ExamRecord> recordById(final Long id) { private Result<ExamRecord> recordById(final Long id) {
@ -681,6 +679,26 @@ public class ExamDAOImpl implements ExamDAO {
}); });
} }
private Collection<EntityDependency> toDependencies(
final List<ExamRecord> 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<Exam> toDomainModelCached(final ExamRecord record) { private Result<Exam> toDomainModelCached(final ExamRecord record) {
return Result.tryCatch(() -> this.lmsAPIService return Result.tryCatch(() -> this.lmsAPIService
.getLmsAPITemplate(record.getLmsSetupId()) .getLmsAPITemplate(record.getLmsSetupId())

View file

@ -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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
@ -220,7 +221,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// only for deletion // only for deletion
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
return Collections.emptySet(); return Collections.emptySet();
@ -231,7 +232,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
} }
// define the select function in case of source type // define the select function in case of source type
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction; Function<EntityKey, Result<Collection<EntityDependency>>> selectionFunction;
switch (bulkAction.sourceType) { switch (bulkAction.sourceType) {
case INSTITUTION: case INSTITUTION:
selectionFunction = this::allIdsOfInstitution; selectionFunction = this::allIdsOfInstitution;
@ -252,8 +253,8 @@ public class IndicatorDAOImpl implements IndicatorDAO {
return getDependencies(bulkAction, selectionFunction); return getDependencies(bulkAction, selectionFunction);
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample()
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
.on( .on(
ExamRecordDynamicSqlSupport.id, ExamRecordDynamicSqlSupport.id,
@ -264,12 +265,16 @@ public class IndicatorDAOImpl implements IndicatorDAO {
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) { private Result<Collection<EntityDependency>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample()
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
.on( .on(
ExamRecordDynamicSqlSupport.id, ExamRecordDynamicSqlSupport.id,
@ -280,12 +285,16 @@ public class IndicatorDAOImpl implements IndicatorDAO {
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) { private Result<Collection<EntityDependency>> allIdsOfUser(final EntityKey userKey) {
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample()
.leftJoin(ExamRecordDynamicSqlSupport.examRecord) .leftJoin(ExamRecordDynamicSqlSupport.examRecord)
.on( .on(
ExamRecordDynamicSqlSupport.id, ExamRecordDynamicSqlSupport.id,
@ -296,19 +305,27 @@ public class IndicatorDAOImpl implements IndicatorDAO {
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }
private Result<Collection<EntityKey>> allIdsOfExam(final EntityKey examKey) { private Result<Collection<EntityDependency>> allIdsOfExam(final EntityKey examKey) {
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.indicatorRecordMapper.selectByExample()
.where( .where(
IndicatorRecordDynamicSqlSupport.examId, IndicatorRecordDynamicSqlSupport.examId,
isEqualTo(Long.parseLong(examKey.modelId))) isEqualTo(Long.parseLong(examKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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.APIMessage.FieldValidationException;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -231,7 +232,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// NOTE since Institution is the top most Entity, there are no other Entity for that an Institution depends on. // NOTE since Institution is the top most Entity, there are no other Entity for that an Institution depends on.
return Collections.emptySet(); return Collections.emptySet();
} }

View file

@ -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;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; 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.ClientCredentialService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.client.ProxyData; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
@ -137,7 +138,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
checkUniqueName(lmsSetup); checkUniqueName(lmsSetup);
LmsSetupRecord savedRecord = recordById(lmsSetup.id) final LmsSetupRecord savedRecord = recordById(lmsSetup.id)
.getOrThrow(); .getOrThrow();
final ClientCredentials lmsCredentials = createAPIClientCredentials(lmsSetup); final ClientCredentials lmsCredentials = createAPIClientCredentials(lmsSetup);
@ -250,7 +251,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// all of institution // all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) { if (bulkAction.sourceType == EntityType.INSTITUTION) {
return getDependencies(bulkAction, this::allIdsOfInstitution); return getDependencies(bulkAction, this::allIdsOfInstitution);
@ -306,14 +307,18 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
}); });
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.lmsSetupRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.lmsSetupRecordMapper.selectByExample()
.where(LmsSetupRecordDynamicSqlSupport.institutionId, .where(LmsSetupRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId))) isEqualTo(Long.valueOf(institutionKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; 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.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.ClientCredentialService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose;
@ -300,7 +301,7 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// all of institution // all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) { if (bulkAction.sourceType == EntityType.INSTITUTION) {
return getDependencies(bulkAction, this::allIdsOfInstitution); return getDependencies(bulkAction, this::allIdsOfInstitution);
@ -326,14 +327,18 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
.map(SebClientConfigRecord::getEncryptSecret); .map(SebClientConfigRecord::getEncryptSecret);
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.sebClientConfigRecordMapper.selectIdsByExample() return Result.tryCatch(() -> this.sebClientConfigRecordMapper.selectByExample()
.where(SebClientConfigRecordDynamicSqlSupport.institutionId, .where(SebClientConfigRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId))) isEqualTo(Long.valueOf(institutionKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.UserAccount; import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
@ -363,7 +364,7 @@ public class UserDAOImpl implements UserDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) { public Set<EntityDependency> getDependencies(final BulkAction bulkAction) {
// all of institution // all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION && if (bulkAction.sourceType == EntityType.INSTITUTION &&
(bulkAction.type == BulkActionType.DEACTIVATE || bulkAction.type == BulkActionType.HARD_DELETE)) { (bulkAction.type == BulkActionType.DEACTIVATE || bulkAction.type == BulkActionType.HARD_DELETE)) {
@ -409,14 +410,18 @@ public class UserDAOImpl implements UserDAO {
} }
} }
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) { private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> this.userRecordMapper.selectByExample() return Result.tryCatch(() -> this.userRecordMapper.selectByExample()
.where(UserRecordDynamicSqlSupport.institutionId, .where(UserRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.modelId))) isEqualTo(Long.valueOf(institutionKey.modelId)))
.build() .build()
.execute() .execute()
.stream() .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())); .collect(Collectors.toList()));
} }

View file

@ -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;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -53,7 +53,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
} }
@Override @Override
public Collection<EntityKey> getDependencies( public Collection<EntityDependency> getDependencies(
final String modelId, final String modelId,
final BulkActionType bulkActionType, final BulkActionType bulkActionType,
final List<String> includes) { final List<String> includes) {

View file

@ -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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; 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.GrantEntity;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
@ -115,7 +115,7 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
} }
@Override @Override
public Collection<EntityKey> getDependencies( public Collection<EntityDependency> getDependencies(
final String modelId, final String modelId,
final BulkActionType bulkActionType, final BulkActionType bulkActionType,
final List<String> includes) { final List<String> includes) {

View file

@ -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;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; 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.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
@ -111,7 +111,7 @@ public class ConfigurationController extends ReadonlyEntityController<Configurat
} }
@Override @Override
public Collection<EntityKey> getDependencies( public Collection<EntityDependency> getDependencies(
final String modelId, final String modelId,
final BulkActionType bulkActionType, final BulkActionType bulkActionType,
final List<String> includes) { final List<String> includes) {

View file

@ -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.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Entity; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityName; import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
@ -209,7 +210,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
method = RequestMethod.GET, method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE) produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Collection<EntityKey> getDependencies( public Collection<EntityDependency> getDependencies(
@PathVariable final String modelId, @PathVariable final String modelId,
@RequestParam(name = API.PARAM_BULK_ACTION_TYPE, required = true) final BulkActionType bulkActionType, @RequestParam(name = API.PARAM_BULK_ACTION_TYPE, required = true) final BulkActionType bulkActionType,
@RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) { @RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) {

View file

@ -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=Confirm New Password
sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password
sebserver.useraccount.delete.form.title=Delete User Account
sebserver.useraccount.delete.form.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.<br/>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 # LMS Setup
################################ ################################

View file

@ -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.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.model.Domain; 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.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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityName; import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
@ -2216,7 +2217,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.findFirst() .findFirst()
.get(); .get();
List<EntityKey> dependencies = restService.getBuilder(GetUserDependency.class) List<EntityDependency> dependencies = restService.getBuilder(GetUserDependency.class)
.withURIVariable(API.PARAM_MODEL_ID, user.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, user.getModelId())
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()) .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name())
.call() .call()
@ -2238,27 +2239,27 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
+ "EXAM_CONFIGURATION_MAP, " + "EXAM_CONFIGURATION_MAP, "
+ "INDICATOR, " + "INDICATOR, "
+ "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 // check that the user is owner of all depending exams and configurations
dependencies.stream() dependencies.stream()
.filter(key -> key.entityType == EntityType.EXAM) .filter(key -> key.self.entityType == EntityType.EXAM)
.forEach(key -> { .forEach(key -> {
assertEquals( assertEquals(
user.modelId, user.modelId,
restService.getBuilder(GetExam.class) restService.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, key.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, key.self.getModelId())
.call() .call()
.getOrThrow().owner); .getOrThrow().owner);
}); });
dependencies.stream() dependencies.stream()
.filter(key -> key.entityType == EntityType.CONFIGURATION_NODE) .filter(key -> key.self.entityType == EntityType.CONFIGURATION_NODE)
.forEach(key -> { .forEach(key -> {
assertEquals( assertEquals(
user.modelId, user.modelId,
restService.getBuilder(GetExamConfigNode.class) restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, key.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, key.self.getModelId())
.call() .call()
.getOrThrow().owner); .getOrThrow().owner);
}); });
@ -2283,7 +2284,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
+ "EXAM_CONFIGURATION_MAP, " + "EXAM_CONFIGURATION_MAP, "
+ "INDICATOR, " + "INDICATOR, "
+ "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 // only with configuration dependencies
dependencies = restService.getBuilder(GetUserDependency.class) dependencies = restService.getBuilder(GetUserDependency.class)
@ -2301,7 +2302,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
+ "CONFIGURATION_NODE, " + "CONFIGURATION_NODE, "
+ "CONFIGURATION_NODE, " + "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 // only with exam and configuration dependencies
dependencies = restService.getBuilder(GetUserDependency.class) dependencies = restService.getBuilder(GetUserDependency.class)
@ -2328,7 +2329,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
+ "EXAM_CONFIGURATION_MAP, " + "EXAM_CONFIGURATION_MAP, "
+ "INDICATOR, " + "INDICATOR, "
+ "INDICATOR]", + "INDICATOR]",
dependencies.stream().map(EntityKey::getEntityType).collect(Collectors.toList()).toString()); dependencies.stream().map(dep -> dep.self.entityType).collect(Collectors.toList()).toString());
} }
@Test @Test

View file

@ -14,6 +14,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test; import org.junit.Test;
import org.springframework.http.HttpMethod; 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.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityName; import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
@ -404,21 +406,23 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
@Test @Test
public void testDependency() throws Exception { public void testDependency() throws Exception {
final Collection<EntityKey> dependencies = new RestAPITestHelper() final Collection<EntityDependency> dependencies = new RestAPITestHelper()
.withAccessToken(getSebAdminAccess()) .withAccessToken(getSebAdminAccess())
.withPath(API.INSTITUTION_ENDPOINT) .withPath(API.INSTITUTION_ENDPOINT)
.withPath("1") .withPath("1")
.withPath(API.DEPENDENCY_PATH_SEGMENT) .withPath(API.DEPENDENCY_PATH_SEGMENT)
.withAttribute(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name()) .withAttribute(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name())
.withExpectedStatus(HttpStatus.OK) .withExpectedStatus(HttpStatus.OK)
.getAsObject(new TypeReference<Collection<EntityKey>>() { .getAsObject(new TypeReference<Collection<EntityDependency>>() {
}); });
final List<EntityKey> depKeys = dependencies.stream().map(dep -> dep.self).collect(Collectors.toList());
assertNotNull(dependencies); assertNotNull(dependencies);
assertTrue(dependencies.size() == 3); assertTrue(dependencies.size() == 3);
assertTrue(dependencies.contains(new EntityKey("user1", EntityType.USER))); assertTrue(depKeys.contains(new EntityKey("user1", EntityType.USER)));
assertTrue(dependencies.contains(new EntityKey("user2", EntityType.USER))); assertTrue(depKeys.contains(new EntityKey("user2", EntityType.USER)));
assertTrue(dependencies.contains(new EntityKey("user5", EntityType.USER))); assertTrue(depKeys.contains(new EntityKey("user5", EntityType.USER)));
} }
static void assertContainsInstitution(final String name, final Collection<Institution> institutions) { static void assertContainsInstitution(final String name, final Collection<Institution> institutions) {