diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java index 905bdedc..585feb6d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java @@ -141,6 +141,7 @@ public final class API { public static final String CONFIGURATION_NODE_ENDPOINT = "/configuration-node"; public static final String CONFIGURATION_FOLLOWUP_PATH_SEGMENT = "/followup"; public static final String CONFIGURATION_CONFIG_KEY_PATH_SEGMENT = "/configkey"; + public static final String CONFIGURATION_SETTINGS_PUBLISHED_PATH_SEGMENT = "/settings_published"; public static final String CONFIGURATION_ENDPOINT = "/configuration"; public static final String CONFIGURATION_SAVE_TO_HISTORY_PATH_SEGMENT = "/save-to-history"; public static final String CONFIGURATION_UNDO_PATH_SEGMENT = "/undo"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SettingsPublished.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SettingsPublished.java new file mode 100644 index 00000000..a797e678 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SettingsPublished.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 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.sebconfig; + +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class SettingsPublished { + + public static final String ATTR_SETTINGS_PUBLISHED = "settingsPublished"; + + @NotNull + @JsonProperty(ATTR_SETTINGS_PUBLISHED) + public final Boolean settingsPublished; + + @JsonCreator + public SettingsPublished(@JsonProperty(ATTR_SETTINGS_PUBLISHED) final Boolean settingsPublished) { + this.settingsPublished = settingsPublished; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java index f78d5356..4d253d44 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java @@ -183,7 +183,7 @@ public class ConfigTemplateAttributeForm implements TemplateComposer { configuration, new View(-1L, "template", 10, 0, templateId), attributeMapping, - 1, false); + 1, false, null); final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder( attribute.getConfigAttribute(), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java index 0ca20d82..68d13c7f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBSettingsForm.java @@ -14,6 +14,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; @@ -46,11 +47,13 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetSettingsPublished; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SEBExamConfigUndo; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; @Lazy @Component @@ -67,6 +70,8 @@ public class SEBSettingsForm implements TemplateComposer { "sebserver.examconfig.action.undo.success"; private static final LocTextKey TITLE_TEXT_KEY = new LocTextKey("sebserver.examconfig.props.from.title"); + private static final LocTextKey UNPUBLISHED_MESSAGE_KEY = + new LocTextKey("sebserver.examconfig.props.from.unpublished.message"); private static final LocTextKey MESSAGE_SAVE_INTEGRITY_VIOLATION = new LocTextKey("sebserver.examconfig.action.saveToHistory.integrity-violation"); @@ -101,6 +106,28 @@ public class SEBSettingsForm implements TemplateComposer { .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) .getOrThrow(); + final boolean settingsPublished = this.restService.getBuilder(GetSettingsPublished.class) + .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) + .call() + .onError(error -> log.warn("Failed to verify published settings. Cause: ", error.getMessage())) + .map(result -> result.settingsPublished) + .getOr(false); + + final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE; + final Composite warningPanelAnchor = new Composite(pageContext.getParent(), SWT.NONE); + final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + warningPanelAnchor.setLayoutData(gridData); + final GridLayout gridLayout = new GridLayout(1, true); + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + warningPanelAnchor.setLayout(gridLayout); + final Runnable publishedMessagePanelViewCallback = this.publishedMessagePanelViewCallback( + warningPanelAnchor, + entityKey.modelId); + if (!settingsPublished) { + publishedMessagePanelViewCallback.run(); + } + final Composite content = widgetFactory.defaultPageLayout( pageContext.getParent(), new LocTextKey(TITLE_TEXT_KEY.name, Utils.truncateText(configNode.name, 30))); @@ -120,7 +147,6 @@ public class SEBSettingsForm implements TemplateComposer { .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error)) .getOrThrow(); - final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE; final List views = this.examConfigurationService.getViews(attributes); final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content); tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); @@ -133,7 +159,8 @@ public class SEBSettingsForm implements TemplateComposer { view, attributes, 20, - readonly); + readonly, + publishedMessagePanelViewCallback); viewContexts.add(viewContext); final Composite viewGrid = this.examConfigurationService.createViewGrid( @@ -218,6 +245,32 @@ public class SEBSettingsForm implements TemplateComposer { } } + private Runnable publishedMessagePanelViewCallback(final Composite parent, final String nodeId) { + return () -> { + if (parent.getChildren() != null && parent.getChildren().length > 0) { + return; + } + + final boolean settingsPublished = this.restService.getBuilder(GetSettingsPublished.class) + .withURIVariable(API.PARAM_MODEL_ID, nodeId) + .call() + .onError(error -> log.warn("Failed to verify published settings. Cause: ", error.getMessage())) + .map(result -> result.settingsPublished) + .getOr(false); + + if (!settingsPublished) { + + final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); + final Composite warningPanel = widgetFactory.createWarningPanel(parent); + widgetFactory.labelLocalized( + warningPanel, + CustomVariant.MESSAGE, + UNPUBLISHED_MESSAGE_KEY); + parent.getParent().layout(); + } + }; + } + private void notifyErrorOnSave(final Exception error, final PageContext context) { if (error instanceof APIMessageError) { try { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java index 616bf7c2..7388331e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java @@ -70,7 +70,7 @@ public interface ExamConfigurationService { /** Create to ViewContext to compose a exam configuration property page, * The ViewContext is the internal state of a exam configuration property page * and is passed through all composers while composing the page. - * + * * @param pageContext The original PageContext that holds the state of the overall page. * @param configuration The configuration on which the exam configuration property page is based on. * @param view The View of the context @@ -84,7 +84,8 @@ public interface ExamConfigurationService { View view, AttributeMapping attributeMapping, int rows, - boolean readonly); + boolean readonly, + Runnable valueChageCallback); Composite createViewGrid( Composite parent, 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 d5f746e6..27bd417a 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 @@ -176,7 +176,8 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { final View view, final AttributeMapping attributeMapping, final int rows, - final boolean readonly) { + final boolean readonly, + final Runnable valueChageCallback) { return new ViewContext( configuration, @@ -187,7 +188,8 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { pageContext, this.restService, this.jsonMapper, - this.valueChangeRules), + this.valueChangeRules, + valueChageCallback), this.widgetFactory.getI18nSupport(), readonly); @@ -323,17 +325,20 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { private final RestService restService; private final JSONMapper jsonMapper; private final Collection valueChangeRules; + private final Runnable valueChageCallback; protected ValueChangeListenerImpl( final PageContext pageContext, final RestService restService, final JSONMapper jsonMapper, - final Collection valueChangeRules) { + final Collection valueChangeRules, + final Runnable valueChageCallback) { this.pageContext = pageContext; this.restService = restService; this.jsonMapper = jsonMapper; this.valueChangeRules = valueChangeRules; + this.valueChageCallback = valueChageCallback; } @Override @@ -367,6 +372,10 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService { } catch (final Exception e) { this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e); } + + if (this.valueChageCallback != null) { + this.valueChageCallback.run(); + } } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetSettingsPublished.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetSettingsPublished.java new file mode 100644 index 00000000..a4fec36c --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetSettingsPublished.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.SettingsPublished; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetSettingsPublished extends RestCall { + + public GetSettingsPublished() { + super(new TypeKey<>( + CallType.UNDEFINED, + EntityType.CONFIGURATION_NODE, + new TypeReference() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CONFIGURATION_NODE_ENDPOINT + + API.MODEL_ID_VAR_PATH_SEGMENT + + API.CONFIGURATION_SETTINGS_PUBLISHED_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index e7e2de2f..685d3612 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -330,12 +330,16 @@ public class WidgetFactory { } public Composite createWarningPanel(final Composite parent) { + return createWarningPanel(parent, 20); + } + + public Composite createWarningPanel(final Composite parent, final int margin) { final Composite composite = new Composite(parent, SWT.NONE); final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); composite.setLayoutData(gridData); final GridLayout gridLayout = new GridLayout(1, true); - gridLayout.marginWidth = 20; - gridLayout.marginHeight = 20; + gridLayout.marginWidth = margin; + gridLayout.marginHeight = margin; composite.setLayout(gridLayout); composite.setData(RWT.CUSTOM_VARIANT, CustomVariant.WARNING.key); return composite; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/ExamConfigService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/ExamConfigService.java index 3e497fe6..89c1dba7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/ExamConfigService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/ExamConfigService.java @@ -124,4 +124,15 @@ public interface ExamConfigService { * @return The newly created Configuration instance */ Result importFromSEBFile(Configuration config, InputStream input, CharSequence password); + /** Use this to check whether a specified ConfigurationNode has unpublished changes within the settings. + * + * This uses the Config Key of the actual and the follow-up settings to verify if there are changes made that + * are not published yet. + * + * @param institutionId the institutional id + * @param configurationNodeId the id if the ConfigurationNode + * @return true if there are unpublished changed in the SEB setting of the follow-up for the specified + * ConfigurationNode */ + Result hasUnpublishedChanged(Long institutionId, Long configurationNodeId); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java index 1095b124..6f60a330 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java @@ -98,11 +98,37 @@ public class ExamConfigIO { final Long institutionId, final Long configurationNodeId) throws Exception { + exportPlain(exportFormat, out, institutionId, configurationNodeId, null); + } + + @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) + void exportForConfigKeyGeneration( + final OutputStream out, + final Long institutionId, + final Long configurationNodeId, + final Long configId) throws Exception { + + exportPlain(ConfigurationFormat.JSON, out, institutionId, configurationNodeId, configId); + } + + private void exportPlain( + final ConfigurationFormat exportFormat, + final OutputStream out, + final Long institutionId, + final Long configurationNodeId, + final Long configId) throws Exception { + if (log.isDebugEnabled()) { log.debug("Start export SEB plain XML configuration asynconously"); } try { + // get configurationId for given configId or configurationNodeId last stable if null + final Long configurationId = (configId == null) + ? this.configurationDAO + .getConfigurationLastStableVersion(configurationNodeId) + .getOrThrow().id + : configId; // get all defined root configuration attributes prepared and sorted final List sortedAttributes = this.configurationAttributeDAO.getAllRootAttributes() @@ -113,11 +139,6 @@ public class ExamConfigIO { .sorted() .collect(Collectors.toList()); - // get follow-up configurationId for given configurationNodeId - final Long configurationId = this.configurationDAO - .getConfigurationLastStableVersion(configurationNodeId) - .getOrThrow().id; - final Function configurationValueSupplier = getConfigurationValueSupplier(institutionId, configurationId); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigServiceImpl.java index fba24d73..144de3f8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigServiceImpl.java @@ -38,6 +38,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationFormat; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator; @@ -61,6 +62,7 @@ public class ExamConfigServiceImpl implements ExamConfigService { private final ClientCredentialService clientCredentialService; private final ZipService zipService; private final SEBConfigEncryptionService sebConfigEncryptionService; + private final ConfigurationDAO configurationDAO; protected ExamConfigServiceImpl( final ExamConfigIO examConfigIO, @@ -69,7 +71,8 @@ public class ExamConfigServiceImpl implements ExamConfigService { final Collection validators, final ClientCredentialService clientCredentialService, final ZipService zipService, - final SEBConfigEncryptionService sebConfigEncryptionService) { + final SEBConfigEncryptionService sebConfigEncryptionService, + final ConfigurationDAO configurationDAO) { this.examConfigIO = examConfigIO; this.configurationAttributeDAO = configurationAttributeDAO; @@ -78,6 +81,7 @@ public class ExamConfigServiceImpl implements ExamConfigService { this.clientCredentialService = clientCredentialService; this.zipService = zipService; this.sebConfigEncryptionService = sebConfigEncryptionService; + this.configurationDAO = configurationDAO; } @Override @@ -249,29 +253,39 @@ public class ExamConfigServiceImpl implements ExamConfigService { final Long institutionId, final Long configurationNodeId) { + return this.configurationDAO + .getConfigurationLastStableVersion(configurationNodeId) + .flatMap(config -> generateConfigKey(institutionId, configurationNodeId, config.id)); + } + + private Result generateConfigKey( + final Long institutionId, + final Long configurationNodeId, + final Long configId) { + if (log.isDebugEnabled()) { log.debug("Start to stream plain JSON SEB Configuration data for Config-Key generation"); } - if (true) { - PipedOutputStream pout; - PipedInputStream pin; - try { - pout = new PipedOutputStream(); - pin = new PipedInputStream(pout); - this.examConfigIO.exportPlain( - ConfigurationFormat.JSON, - pout, - institutionId, - configurationNodeId); - - final String json = IOUtils.toString(pin, "UTF-8"); - - log.trace("SEB Configuration JSON to create Config-Key: {}", json); - } catch (final Exception e) { - log.error("Failed to trace SEB Configuration JSON: ", e); - } - } +// if (true) { +// PipedOutputStream pout; +// PipedInputStream pin; +// try { +// pout = new PipedOutputStream(); +// pin = new PipedInputStream(pout); +// this.examConfigIO.exportPlain( +// ConfigurationFormat.JSON, +// pout, +// institutionId, +// configurationNodeId); +// +// final String json = IOUtils.toString(pin, "UTF-8"); +// +// log.trace("SEB Configuration JSON to create Config-Key: {}", json); +// } catch (final Exception e) { +// log.error("Failed to trace SEB Configuration JSON: ", e); +// } +// } PipedOutputStream pout = null; PipedInputStream pin = null; @@ -279,11 +293,11 @@ public class ExamConfigServiceImpl implements ExamConfigService { pout = new PipedOutputStream(); pin = new PipedInputStream(pout); - this.examConfigIO.exportPlain( - ConfigurationFormat.JSON, + this.examConfigIO.exportForConfigKeyGeneration( pout, institutionId, - configurationNodeId); + configurationNodeId, + configId); final String configKey = DigestUtils.sha256Hex(pin); @@ -380,6 +394,23 @@ public class ExamConfigServiceImpl implements ExamConfigService { }); } + @Override + public Result hasUnpublishedChanged(final Long institutionId, final Long configurationNodeId) { + return Result.tryCatch(() -> { + + final String followupKey = this.configurationDAO + .getFollowupConfiguration(configurationNodeId) + .flatMap(config -> generateConfigKey(institutionId, configurationNodeId, config.id)) + .getOrThrow(); + final String stableKey = this.configurationDAO + .getConfigurationLastStableVersion(configurationNodeId) + .flatMap(config -> generateConfigKey(institutionId, configurationNodeId, config.id)) + .getOrThrow(); + + return !followupKey.equals(stableKey); + }); + } + private void exportPlainOnly( final ConfigurationFormat exportFormat, final OutputStream out, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationNodeController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationNodeController.java index 6a8380a7..de9b53bf 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationNodeController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationNodeController.java @@ -50,6 +50,7 @@ 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.SettingsPublished; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -142,6 +143,28 @@ public class ConfigurationNodeController extends EntityController new SettingsPublished(!flag)) + .getOrThrow(); + } + @RequestMapping( path = API.CONFIGURATION_COPY_PATH_SEGMENT, method = RequestMethod.PUT, diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 536b6e35..2c90b6d7 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -789,6 +789,7 @@ sebserver.examconfig.status.CONSTRUCTION=Under Construction sebserver.examconfig.status.READY_TO_USE=Ready To Use sebserver.examconfig.status.IN_USE=In Use +sebserver.examconfig.props.from.unpublished.message=Note: There are unpublished changes to this Settings. Use 'Save/Publish Settings' to make sure the settings are active. sebserver.examconfig.props.from.title=Exam Configuration Settings ({0}) sebserver.examconfig.props.from.title.subtitle= sebserver.examconfig.props.form.views.general=General