From 3b4c168c436ed9e6a5c99455b7e056bf5d3b4e9b Mon Sep 17 00:00:00 2001 From: anhefti Date: Thu, 16 Jun 2022 10:56:42 +0200 Subject: [PATCH] SEBSERV-218 implemented --- .../content/configs/ConfigTemplateForm.java | 95 +++++++++++++++++-- .../impl/ExamConfigurationServiceImpl.java | 19 +++- .../seb/sebserver/gui/table/EntityTable.java | 4 + .../dao/NoResourceFoundException.java | 27 ++++++ .../impl/ExamConfigTemplateServiceImpl.java | 20 +++- .../proctoring/ZoomProctoringService.java | 1 - src/main/resources/messages.properties | 5 + 7 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/NoResourceFoundException.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/configs/ConfigTemplateForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/configs/ConfigTemplateForm.java index b55e7959..263d90f3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/configs/ConfigTemplateForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/configs/ConfigTemplateForm.java @@ -8,6 +8,10 @@ package ch.ethz.seb.sebserver.gui.content.configs; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.widgets.Composite; import org.springframework.context.annotation.Lazy; @@ -19,13 +23,16 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; +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.ConfigurationStatus; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormHandle; @@ -40,6 +47,8 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.DeleteExamConfiguration; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues; +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.GetTemplateAttributePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; @@ -75,6 +84,8 @@ public class ConfigTemplateForm implements TemplateComposer { new LocTextKey("sebserver.configtemplate.attrs.list.view"); private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attrs.list.group"); + private static final LocTextKey ATTRIBUTES_LIST_VALUE_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.attrs.list.value"); private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attrs.list.type"); private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY = @@ -205,6 +216,20 @@ public class ConfigTemplateForm implements TemplateComposer { TemplateAttribute.FILTER_ATTR_TYPE, this.resourceService::getAttributeTypeResources); + // TODO move this to an supplier that also can be updated + // the follow-up configuration + final Configuration configuration = this.restService + .getBuilder(GetConfigurations.class) + .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, examConfig.getModelId()) + .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING) + .call() + .map(Utils::toSingleton) + .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error)) + .getOrThrow(); + final AttributeValueSupplier attributeValueSupplier = new AttributeValueSupplier( + this.pageService, + configuration.getModelId()); + final EntityTable attrTable = this.pageService.entityTableBuilder( Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template", @@ -213,6 +238,7 @@ public class ConfigTemplateForm implements TemplateComposer { API.PARAM_PARENT_MODEL_ID, entityKey.modelId)) .withPaging(15) + .withColumn(new ColumnDefinition<>( Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, ATTRIBUTES_LIST_NAME_TEXT_KEY, @@ -220,6 +246,7 @@ public class ConfigTemplateForm implements TemplateComposer { .withFilter(this.nameFilter) .sortable() .widthProportion(3)) + .withColumn(new ColumnDefinition( Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, ATTRIBUTES_LIST_TYPE_TEXT_KEY, @@ -227,6 +254,7 @@ public class ConfigTemplateForm implements TemplateComposer { .withFilter(typeFilter) .sortable() .widthProportion(1)) + .withColumn(new ColumnDefinition<>( Domain.ORIENTATION.ATTR_VIEW_ID, ATTRIBUTES_LIST_VIEW_TEXT_KEY, @@ -234,6 +262,7 @@ public class ConfigTemplateForm implements TemplateComposer { .withFilter(viewFilter) .sortable() .widthProportion(1)) + .withColumn(new ColumnDefinition<>( Domain.ORIENTATION.ATTR_GROUP_ID, ATTRIBUTES_LIST_GROUP_TEXT_KEY, @@ -241,6 +270,13 @@ public class ConfigTemplateForm implements TemplateComposer { .withFilter(this.groupFilter) .sortable() .widthProportion(1)) + + .withColumn(new ColumnDefinition( + Domain.CONFIGURATION_VALUE.ATTR_VALUE, + ATTRIBUTES_LIST_VALUE_TEXT_KEY, + attr -> attributeValueSupplier.getAttributeValue(attr.getConfigAttribute().id)) + .widthProportion(1)) + .withDefaultActionIf( () -> modifyGrant, () -> pageActionBuilder @@ -271,7 +307,7 @@ public class ConfigTemplateForm implements TemplateComposer { .withParentEntityKey(entityKey) .withSelect( attrTable::getMultiSelection, - action -> this.resetToDefaults(action, attrTable), + action -> this.resetToDefaults(attributeValueSupplier, action, attrTable), EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .noEventPropagation() .publishIf(() -> modifyGrant, false) @@ -378,12 +414,14 @@ public class ConfigTemplateForm implements TemplateComposer { } private PageAction resetToDefaults( + final AttributeValueSupplier attributeValueSupplier, final PageAction action, final EntityTable attrTable) { final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action); // reload the list - attrTable.applyFilter(); + attributeValueSupplier.update(); + attrTable.updateCurrentPage(); return resetToDefaults; } @@ -392,8 +430,8 @@ public class ConfigTemplateForm implements TemplateComposer { final EntityTable attrTable) { final PageAction removeFormView = this.examConfigurationService.removeFromView(action); - // reload the list - attrTable.applyFilter(); + // reload the page + attrTable.updateCurrentPage(); return removeFormView; } @@ -402,9 +440,54 @@ public class ConfigTemplateForm implements TemplateComposer { final EntityTable attrTable) { final PageAction attachView = this.examConfigurationService.attachToDefaultView(action); - // reload the list - attrTable.applyFilter(); + // reload the page + attrTable.updateCurrentPage(); return attachView; } + private final class AttributeValueSupplier { + + private final PageService pageService; + private final String configurationId; + private final Map attrValueMapping = new HashMap<>(); + + public AttributeValueSupplier( + final PageService pageService, + final String configurationId) { + + this.pageService = pageService; + this.configurationId = configurationId; + update(); + } + + public String getAttributeValue(final Long attributeId) { + if (this.attrValueMapping.containsKey(attributeId)) { + return this.attrValueMapping.get(attributeId); + } else { + return Constants.EMPTY_NOTE; + } + } + + private void update() { + this.attrValueMapping.clear(); + + this.pageService.getRestService() + .getBuilder(GetConfigurationValues.class) + .withQueryParam( + ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, + this.configurationId) + .call() + .getOrElse(Collections::emptyList) + .stream() + .forEach(val -> { + if (this.attrValueMapping.containsKey(val.attributeId)) { + this.attrValueMapping.put(val.attributeId, + this.attrValueMapping.get(val.attributeId) + "," + val.value); + } else { + this.attrValueMapping.put(val.attributeId, val.value); + } + }); + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/ExamConfigurationServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/ExamConfigurationServiceImpl.java index b27c63cf..095a0089 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/ExamConfigurationServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/ExamConfigurationServiceImpl.java @@ -72,6 +72,11 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class); + public static final LocTextKey ACTION_ERROR_TITLE = + new LocTextKey("sebserver.configtemplate.action.error.title"); + public static final LocTextKey ACTION_ERROR_MSG = + new LocTextKey("sebserver.configtemplate.action.error.noview.message"); + private final RestService restService; private final JSONMapper jsonMapper; private final WidgetFactory widgetFactory; @@ -254,12 +259,14 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { final Set selection = action.getMultiSelection(); if (selection != null && !selection.isEmpty()) { selection.forEach(entityKey -> callTemplateAction( + action, ResetTemplateValues.class, parentEntityKey.modelId, entityKey.modelId)); } else { final EntityKey entityKey = action.getEntityKey(); callTemplateAction( + action, ResetTemplateValues.class, parentEntityKey.modelId, entityKey.modelId); @@ -274,12 +281,14 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { final Set selection = action.getMultiSelection(); if (selection != null && !selection.isEmpty()) { selection.forEach(entityKey -> callTemplateAction( + action, RemoveOrientation.class, parentEntityKey.modelId, entityKey.modelId)); } else { final EntityKey entityKey = action.getEntityKey(); callTemplateAction( + action, RemoveOrientation.class, parentEntityKey.modelId, entityKey.modelId); @@ -294,21 +303,23 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { final Set selection = action.getMultiSelection(); if (selection != null && !selection.isEmpty()) { selection.forEach(entityKey -> callTemplateAction( + action, AttachDefaultOrientation.class, parentEntityKey.modelId, entityKey.modelId)); } else { final EntityKey entityKey = action.getEntityKey(); callTemplateAction( + action, AttachDefaultOrientation.class, parentEntityKey.modelId, entityKey.modelId); } - return action; } private void callTemplateAction( + final PageAction action, final Class> actionType, final String templateId, final String attributeId) { @@ -317,7 +328,11 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { .withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId) .withURIVariable(API.PARAM_MODEL_ID, attributeId) .call() - .getOrThrow(); + .onError(error -> { + action.pageContext().publishPageMessage( + ACTION_ERROR_TITLE, + ACTION_ERROR_MSG); + }); } private static final class ValueChangeListenerImpl implements ValueChangeListener { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index 222dddce..8eb9a1d7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -300,6 +300,10 @@ public class EntityTable { applyFilter(); } + public void updateCurrentPage() { + this.selectPage(this.pageNumber); + } + public void applyFilter() { try { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/NoResourceFoundException.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/NoResourceFoundException.java new file mode 100644 index 00000000..07ed3de3 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/NoResourceFoundException.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.webservice.servicelayer.dao; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +import ch.ethz.seb.sebserver.gbl.api.EntityType; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class NoResourceFoundException extends RuntimeException { + + private static final long serialVersionUID = 4347712679241097195L; + public final EntityType entityType; + + public NoResourceFoundException(final EntityType entityType, final String message) { + super("Resource " + entityType + " not found: " + message); + this.entityType = entityType; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigTemplateServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigTemplateServiceImpl.java index 8aa340b4..a33d2581 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigTemplateServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigTemplateServiceImpl.java @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; @@ -39,6 +40,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeD import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationValueDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.NoResourceFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.OrientationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ViewDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigTemplateService; @@ -172,7 +174,13 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService return Result.tryCatch(() -> { final Orientation orientation = getOrientation(templateId, attributeId); - this.orientationDAO.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) + if (orientation == null) { + throw new NoResourceFoundException(EntityType.ORIENTATION, + "No default view found for attribute: " + attributeId); + } + + this.orientationDAO + .delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) .getOrThrow(); final TemplateAttribute attribute = getAttribute(institutionId, templateId, attributeId) @@ -198,8 +206,14 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService final Orientation orientation = getOrientation(templateId, attributeId); final Orientation devOrientation = getOrientation(ConfigurationNode.DEFAULT_TEMPLATE_ID, attributeId); + if (devOrientation == null) { + throw new NoResourceFoundException(EntityType.ORIENTATION, + "No default view found for attribute: " + attributeId); + } + if (orientation != null) { - this.orientationDAO.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) + this.orientationDAO + .delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) .getOrThrow(); } @@ -246,7 +260,7 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService return this.orientationDAO.allMatching(filterMap) .get(error -> { - log.warn("Unexpecrted error while get Orientation: ", error); + log.warn("Unexpected error while get Orientation: ", error); return Collections.emptyList(); }) .stream() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java index 3be70848..3227938b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java @@ -455,7 +455,6 @@ public class ZoomProctoringService implements ExamProctoringService { e); } }); - } @Override diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index eda924a6..aab5b066 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -1667,7 +1667,11 @@ sebserver.configtemplate.attrs.list.group=Group sebserver.configtemplate.attrs.list.group.tooltip=The group on the view/tab where the exam configuration attribute belongs to

{0} sebserver.configtemplate.attrs.list.type=Type sebserver.configtemplate.attrs.list.type.tooltip=The type of the exam configuration attribute

{0} +sebserver.configtemplate.attrs.list.value=Value +sebserver.configtemplate.attrs.list.value.tooltip=The settings value that is set as default value for this template +sebserver.configtemplate.action.error.title=Action Failed +sebserver.configtemplate.action.error.noview.message=This setting has no default view
and cannot be attached/detached from a view sebserver.configtemplate.attr.list.actions= sebserver.configtemplate.attr.list.actions.modify=Edit Attribute sebserver.configtemplate.attr.list.actions.setdefault=Set Default Values @@ -1675,6 +1679,7 @@ sebserver.configtemplate.attr.list.actions.removeview=Remove From View sebserver.configtemplate.attr.list.actions.attach-default-view=Attach To View sebserver.configtemplate.attr.info.pleaseSelect=At first please select an Attribute from the list + sebserver.configtemplate.attr.form.title=Configuration Template Attribute sebserver.configtemplate.attr.form.title.subtitle= sebserver.configtemplate.attr.form.name=Name