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 34a28ad6..f8eb51bc 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 @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.gbl.api; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; + public final class API { public enum BulkActionType { @@ -25,6 +27,7 @@ public final class API { public static final String PARAM_ENTITY_TYPE = "entityType"; public static final String PARAM_BULK_ACTION_TYPE = "bulkActionType"; public static final String PARAM_CLIENT_CONFIG_SECRET = "client_config_secret"; + public static final String DEFAULT_CONFIG_TEMPLATE_ID = String.valueOf(ConfigurationNode.DEFAULT_TEMPLATE_ID); public static final String INSTITUTION_VAR_PATH_SEGMENT = "/{" + PARAM_INSTITUTION_ID + "}"; public static final String MODEL_ID_VAR_PATH_SEGMENT = "/{" + PARAM_MODEL_ID + "}"; @@ -124,6 +127,10 @@ public final class API { public static final String IMPORT_PASSWORD_ATTR_NAME = "importFilePassword"; public static final String IMPORT_FILE_ATTR_NAME = "importFile"; + public static final String TEMPLATE_ATTRIBUTE_ENDPOINT = "/template-attribute"; + + public static final String CONFIGURATION_TEMPLATE_ENDPOINT = "/exam-config-template"; + public static final String ORIENTATION_ENDPOINT = "/orientation"; public static final String VIEW_ENDPOINT = ORIENTATION_ENDPOINT + "/view"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TemplateAttribute.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TemplateAttribute.java new file mode 100644 index 00000000..5a4c1687 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TemplateAttribute.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2019 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 java.util.Comparator; + +import javax.validation.constraints.NotNull; + +import org.apache.commons.lang3.StringUtils; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.Domain.CONFIGURATION; +import ch.ethz.seb.sebserver.gbl.model.Entity; + +public final class TemplateAttribute implements Entity { + + public static final String ATTR_CONFIG_ATTRIBUTE = "configAttribute"; + public static final String ATTR_ORIENTATION = "orientation"; + + public static final String FILTER_ATTR_VIEW = "view"; + public static final String FILTER_ATTR_GROUP = "group"; + + @NotNull + @JsonProperty(CONFIGURATION.ATTR_INSTITUTION_ID) + public final Long institutionId; + + @NotNull + @JsonProperty(CONFIGURATION.ATTR_CONFIGURATION_NODE_ID) + public final Long templateId; + + @NotNull + @JsonProperty(ATTR_CONFIG_ATTRIBUTE) + private final ConfigurationAttribute configAttribute; + + @JsonProperty(ATTR_ORIENTATION) + private final Orientation orientation; + + public TemplateAttribute( + @JsonProperty(CONFIGURATION.ATTR_INSTITUTION_ID) final Long institutionId, + @JsonProperty(CONFIGURATION.ATTR_CONFIGURATION_NODE_ID) final Long templateId, + @JsonProperty(ATTR_CONFIG_ATTRIBUTE) final ConfigurationAttribute configAttribute, + @JsonProperty(ATTR_ORIENTATION) final Orientation orientation) { + + this.institutionId = institutionId; + this.templateId = templateId; + this.configAttribute = configAttribute; + this.orientation = orientation; + } + + @Override + public String getModelId() { + return this.institutionId != null + ? String.valueOf(this.institutionId) + : null; + } + + @Override + public EntityType entityType() { + return EntityType.CONFIGURATION_NODE; + } + + @Override + public String getName() { + return this.configAttribute.name; + } + + public Long getInstitutionId() { + return this.institutionId; + } + + public Long getTemplateId() { + return this.templateId; + } + + public ConfigurationAttribute getConfigAttribute() { + return this.configAttribute; + } + + public Orientation getOrientation() { + return this.orientation; + } + + @JsonIgnore + public String getViewModelId() { + if (this.orientation == null || this.orientation.viewId == null) { + return null; + } + + return String.valueOf(this.orientation.viewId); + } + + @JsonIgnore + public String getGroupId() { + if (this.orientation == null) { + return null; + } + + return this.orientation.groupId; + } + + @JsonIgnore + public boolean isNameLike(final String name) { + if (StringUtils.isBlank(name)) { + return true; + } + return this.configAttribute.name.contains(name); + } + + @JsonIgnore + public boolean isInView(final Long viewId) { + if (viewId == null) { + return true; + } + return this.orientation != null && this.orientation.viewId.equals(viewId); + } + + @JsonIgnore + public boolean isGroupLike(final String groupId) { + if (StringUtils.isBlank(groupId)) { + return true; + } + return this.orientation != null + && this.orientation.groupId != null + && this.orientation.groupId.contains(groupId); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("TemplateAttribute [institutionId="); + builder.append(this.institutionId); + builder.append(", templateId="); + builder.append(this.templateId); + builder.append(", configAttribute="); + builder.append(this.configAttribute); + builder.append(", orientation="); + builder.append(this.orientation); + builder.append("]"); + return builder.toString(); + } + + public static final Comparator nameComparator(final boolean descending) { + return (attr1, attr2) -> attr1.configAttribute.name.compareToIgnoreCase( + attr2.configAttribute.name) * ((descending) ? -1 : 1); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java index 910aa9cd..44d66f46 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java @@ -22,6 +22,8 @@ import ch.ethz.seb.sebserver.gbl.model.Entity; @JsonIgnoreProperties(ignoreUnknown = true) public class View implements Entity { + public static final String FILTER_ATTR_TEMPLATE = "templateId"; + @JsonProperty(VIEW.ATTR_ID) public final Long id; 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 new file mode 100644 index 00000000..427287c2 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateAttributeForm.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 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 org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.ResourceService; +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.TemplateComposer; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; + +@Lazy +@Component +@GuiProfile +public class ConfigTemplateAttributeForm implements TemplateComposer { + + private final PageService pageService; + private final RestService restService; + private final CurrentUser currentUser; + private final ResourceService resourceService; + + protected ConfigTemplateAttributeForm( + final PageService pageService, + final RestService restService, + final CurrentUser currentUser) { + + this.pageService = pageService; + this.restService = restService; + this.currentUser = currentUser; + this.resourceService = pageService.getResourceService(); + + } + + @Override + public void compose(final PageContext pageContext) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java new file mode 100644 index 00000000..62ec1ef1 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2019 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.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.eclipse.swt.widgets.Composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; +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.TemplateAttribute; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +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; +import ch.ethz.seb.sebserver.gui.service.ResourceService; +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.TemplateComposer; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; +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; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; +import ch.ethz.seb.sebserver.gui.table.EntityTable; +import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +@Lazy +@Component +@GuiProfile +public class ConfigTemplateForm implements TemplateComposer { + + private static final Logger log = LoggerFactory.getLogger(ConfigTemplateForm.class); + + private static final LocTextKey FORM_TITLE_NEW = + new LocTextKey("sebserver.configtemplate.form.title.new"); + private static final LocTextKey FORM_TITLE = + new LocTextKey("sebserver.configtemplate.form.title"); + private static final LocTextKey FORM_NAME_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.form.name"); + private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.form.description"); + private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.attrs.list.title"); + private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.attrs.list.name"); + private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.attrs.list.view"); + private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.attrs.list.group"); + + private final PageService pageService; + private final RestService restService; + private final CurrentUser currentUser; + private final ResourceService resourceService; + + private final TableFilterAttribute nameFilter = + new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_NAME); + private final TableFilterAttribute groupFilter = + new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_GROUP); + + protected ConfigTemplateForm( + final PageService pageService, + final RestService restService, + final CurrentUser currentUser) { + + this.pageService = pageService; + this.restService = restService; + this.currentUser = currentUser; + this.resourceService = pageService.getResourceService(); + + } + + @Override + public void compose(final PageContext pageContext) { + + final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); + final ResourceService resourceService = this.pageService.getResourceService(); + + final UserInfo user = this.currentUser.get(); + final EntityKey entityKey = pageContext.getEntityKey(); + final boolean isNew = entityKey == null; + + // get data or create new. Handle error if happen + final ConfigurationNode examConfig = (isNew) + ? ConfigurationNode.createNewTemplate(user.institutionId) + : this.restService + .getBuilder(GetExamConfigNode.class) + .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) + .call() + .get(pageContext::notifyError); + + if (examConfig == null) { + log.error("Failed to get ConfigurationNode for Template. " + + "Error was notified to the User. " + + "See previous logs for more infomation"); + return; + } + + final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig); + final boolean writeGrant = entityGrant.w(); + final boolean modifyGrant = entityGrant.m(); + final boolean isReadonly = pageContext.isReadonly(); + + // new PageContext with actual EntityKey + final PageContext formContext = pageContext + .withEntityKey(examConfig.getEntityKey()); + + // the default page layout with interactive title + final LocTextKey titleKey = (isNew) + ? FORM_TITLE_NEW + : FORM_TITLE; + final Composite content = widgetFactory.defaultPageLayout( + formContext.getParent(), + titleKey); + + // The SebClientConfig form + final FormHandle formHandle = this.pageService.formBuilder( + formContext.copyOf(content), 4) + .readonly(isReadonly) + .putStaticValueIf(() -> !isNew, + Domain.CONFIGURATION_NODE.ATTR_ID, + examConfig.getModelId()) + .putStaticValue( + Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID, + String.valueOf(examConfig.getInstitutionId())) + .putStaticValue( + Domain.CONFIGURATION_NODE.ATTR_TYPE, + ConfigurationType.TEMPLATE.name()) + .putStaticValue( + Domain.CONFIGURATION_NODE.ATTR_STATUS, + ConfigurationStatus.IN_USE.name()) + .addField(FormBuilder.text( + Domain.CONFIGURATION_NODE.ATTR_NAME, + FORM_NAME_TEXT_KEY, + examConfig.name)) + .addField(FormBuilder.text( + Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, + FORM_DESCRIPTION_TEXT_KEY, + examConfig.description) + .asArea()) + .buildFor((isNew) + ? this.restService.getRestCall(NewExamConfig.class) + : this.restService.getRestCall(SaveExamConfig.class)); + + if (isReadonly) { + + widgetFactory.label(content, ""); + widgetFactory.labelLocalizedTitle( + content, + ATTRIBUTES_LIST_TITLE_TEXT_KEY); + + final TableFilterAttribute viewFilter = new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + TemplateAttribute.FILTER_ATTR_VIEW, + () -> this.resourceService.getViewResources(entityKey.modelId)); + + final EntityTable attrTable = + this.pageService.entityTableBuilder(this.restService.getRestCall(GetTemplateAttributePage.class)) + .withRestCallAdapter(restCall -> restCall.withURIVariable( + API.PARAM_MODEL_ID, + entityKey.modelId)) + .withPaging(15) + .withColumn(new ColumnDefinition<>( + Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, + ATTRIBUTES_LIST_NAME_TEXT_KEY, + TemplateAttribute::getName) + .withFilter(this.nameFilter) + .sortable()) + .withColumn(new ColumnDefinition<>( + Domain.ORIENTATION.ATTR_VIEW_ID, + ATTRIBUTES_LIST_VIEW_TEXT_KEY, + getViewNameFunction(entityKey)) + .withFilter(viewFilter) + .sortable()) + .withColumn(new ColumnDefinition<>( + Domain.ORIENTATION.ATTR_GROUP_ID, + ATTRIBUTES_LIST_GROUP_TEXT_KEY, + TemplateAttribute::getGroupId) + .withFilter(this.groupFilter) + .sortable()) +// .withDefaultAction(pageActionBuilder +// .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) +// .create()) + .compose(pageContext.copyOf(content)); + + // TODO list of all attributes with filter + } + + this.pageService.pageActionBuilder(formContext.clearEntityKeys()) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW) + .publishIf(() -> writeGrant && isReadonly) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY) + .withEntityKey(entityKey) + .publishIf(() -> modifyGrant && isReadonly) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_SAVE) + .withEntityKey(entityKey) + .withExec(formHandle::processFormSave) + .ignoreMoveAwayFromEdit() + .publishIf(() -> !isReadonly) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY) + .withEntityKey(entityKey) + .withExec(this.pageService.backToCurrentFunction()) + .publishIf(() -> !isReadonly); + + } + + private final Function getViewNameFunction(final EntityKey templateId) { + final Map mapping = this.resourceService.getViewResources(templateId.modelId) + .stream() + .collect(Collectors.toMap(tuple -> tuple._1, tuple -> tuple._2)); + + return attr -> mapping.get(attr.getViewModelId()); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java index 03613e3e..01320235 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java @@ -9,7 +9,6 @@ package ch.ethz.seb.sebserver.gui.content; import org.eclipse.swt.widgets.Composite; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -17,6 +16,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Entity; 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.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; @@ -35,6 +35,7 @@ import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @Lazy @Component @@ -43,10 +44,14 @@ public class SebExamConfigList implements TemplateComposer { private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege"); - private static final LocTextKey EMPTY_LIST_TEXT_KEY = + private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY = new LocTextKey("sebserver.examconfig.list.empty"); - private static final LocTextKey TITLE_TEXT_KEY = + private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.list.empty"); + private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY = new LocTextKey("sebserver.examconfig.list.title"); + private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.list.title"); private static final LocTextKey INSTITUTION_TEXT_KEY = new LocTextKey("sebserver.examconfig.list.column.institution"); private static final LocTextKey NAME_TEXT_KEY = @@ -57,6 +62,8 @@ public class SebExamConfigList implements TemplateComposer { new LocTextKey("sebserver.examconfig.list.column.status"); private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.examconfig.info.pleaseSelect"); + private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY = + new LocTextKey("sebserver.configtemplate.info.pleaseSelect"); private final TableFilterAttribute institutionFilter; private final TableFilterAttribute nameFilter = @@ -67,19 +74,16 @@ public class SebExamConfigList implements TemplateComposer { private final RestService restService; private final CurrentUser currentUser; private final ResourceService resourceService; - private final int pageSize; protected SebExamConfigList( final PageService pageService, final RestService restService, - final CurrentUser currentUser, - @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { + final CurrentUser currentUser) { this.pageService = pageService; this.restService = restService; this.currentUser = currentUser; this.resourceService = pageService.getResourceService(); - this.pageSize = pageSize; this.institutionFilter = new TableFilterAttribute( CriteriaType.SINGLE_SELECTION, @@ -94,20 +98,24 @@ public class SebExamConfigList implements TemplateComposer { @Override public void compose(final PageContext pageContext) { + final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); - final Composite content = this.pageService.getWidgetFactory().defaultPageLayout( + final Composite content = widgetFactory.defaultPageLayout( pageContext.getParent(), - TITLE_TEXT_KEY); + TITLE_CONFIGURATION_TEXT_KEY); final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final PageActionBuilder pageActionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); - // table - final EntityTable table = + // exam configuration table + final EntityTable configTable = this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) - .withEmptyMessage(EMPTY_LIST_TEXT_KEY) - .withPaging(this.pageSize) + .withStaticFilter( + Domain.CONFIGURATION_NODE.ATTR_TYPE, + ConfigurationType.EXAM_CONFIG.name()) + .withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY) + .withPaging(6) .withColumnIf( () -> isSEBAdmin, () -> new ColumnDefinition<>( @@ -139,27 +147,80 @@ public class SebExamConfigList implements TemplateComposer { .create()) .compose(pageContext.copyOf(content)); + // configuration template table + widgetFactory.label(content, ""); + widgetFactory.labelLocalizedTitle( + content, + TITLE_TEMPLATE_TEXT_KEY); + + final EntityTable templateTable = + this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) + .withStaticFilter( + Domain.CONFIGURATION_NODE.ATTR_TYPE, + ConfigurationType.TEMPLATE.name()) + .withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY) + .withPaging(6) + .withColumnIf( + () -> isSEBAdmin, + () -> new ColumnDefinition<>( + Domain.LMS_SETUP.ATTR_INSTITUTION_ID, + INSTITUTION_TEXT_KEY, + this.resourceService::localizedExamConfigInstitutionName) + .withFilter(this.institutionFilter) + .sortable()) + .withColumn(new ColumnDefinition<>( + Domain.CONFIGURATION_NODE.ATTR_NAME, + NAME_TEXT_KEY, + ConfigurationNode::getName) + .withFilter(this.nameFilter) + .sortable()) + .withColumn(new ColumnDefinition<>( + Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, + DESCRIPTION_TEXT_KEY, + ConfigurationNode::getDescription) + .withFilter(this.nameFilter) + .sortable()) + .withDefaultAction(pageActionBuilder + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) + .create()) + .compose(pageContext.copyOf(content)); + final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); pageActionBuilder - + // Exam Configuration actions... .newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW) .publishIf(examConfigGrant::iw) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> table.hasAnyContent()) + .withSelect(configTable::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .publishIf(() -> configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .withSelect( - table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> examConfigGrant.im() && table.hasAnyContent()) + .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST) .withSelect( - table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> examConfigGrant.im() && table.hasAnyContent()); + .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) + + // Exam Configuration template actions... + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW) + .publishIf(examConfigGrant::iw) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) + .withSelect(templateTable::getSelection, PageAction::applySingleSelection, + EMPTY_TEMPLATE_SELECTION_TEXT_KEY) + .publishIf(() -> templateTable.hasAnyContent()) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST) + .withSelect( + templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + PageAction::applySingleSelection, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) + .publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent()); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java index a4befea3..8b7e6f80 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java @@ -113,15 +113,11 @@ public class SebExamConfigPropForm implements TemplateComposer { final UserInfo user = this.currentUser.get(); final EntityKey entityKey = pageContext.getEntityKey(); - final EntityKey parentEntityKey = pageContext.getParentEntityKey(); - final boolean isNew = entityKey == null; // get data or create new. Handle error if happen final ConfigurationNode examConfig = (isNew) - ? ConfigurationNode.createNewExamConfig((parentEntityKey != null) - ? Long.valueOf(parentEntityKey.modelId) - : user.institutionId) + ? ConfigurationNode.createNewExamConfig(user.institutionId) : this.restService .getBuilder(GetExamConfigNode.class) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java index 8cacbc0e..1af35eb3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java @@ -21,6 +21,8 @@ public enum ActionCategory { INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2), SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1), SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1), + SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 2), + SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1), RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1), CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1), LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index 0a5ea2a8..750fd402 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -415,6 +415,58 @@ public enum ActionDefinition { PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT, ActionCategory.FORM), + SEB_EXAM_CONFIG_TEMPLATE_NEW( + new LocTextKey("sebserver.exam.configtemplate.action.list.new"), + ImageIcon.NEW, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_EDIT, + ActionCategory.VARIA), + SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST( + new LocTextKey("sebserver.configtemplate.action.list.view"), + ImageIcon.SHOW, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_VIEW, + ActionCategory.SEB_CONFIG_TEMPLATE_LIST), + SEB_EXAM_CONFIG_TEMPLATE_VIEW( + new LocTextKey("sebserver.configtemplate.action.view"), + ImageIcon.SHOW, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_VIEW, + ActionCategory.FORM), + SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST( + new LocTextKey("sebserver.configtemplate.action.list.modify"), + ImageIcon.EDIT, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_EDIT, + ActionCategory.SEB_CONFIG_TEMPLATE_LIST), + SEB_EXAM_CONFIG_TEMPLATE_MODIFY( + new LocTextKey("sebserver.configtemplate.action.modify"), + ImageIcon.EDIT, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_EDIT, + ActionCategory.FORM), + SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY( + new LocTextKey("sebserver.overall.action.modify.cancel"), + ImageIcon.CANCEL, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_VIEW, + ActionCategory.FORM), + SEB_EXAM_CONFIG_TEMPLATE_SAVE( + new LocTextKey("sebserver.configtemplate.action.save"), + ImageIcon.SAVE, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_VIEW, + ActionCategory.FORM), + + SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT( + new LocTextKey("sebserver.configtemplate.attr.list.actions.modify"), + ImageIcon.EDIT, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_VIEW, + ActionCategory.SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST), + SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT( + new LocTextKey("sebserver.configtemplate.attr.list.actions.setdefault"), + ImageIcon.SAVE, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_VIEW, + ActionCategory.SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST), + SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW( + new LocTextKey("sebserver.configtemplate.attr.list.actions.removeview"), + ImageIcon.DELETE, + PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_VIEW, + ActionCategory.SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST), + RUNNING_EXAM_VIEW_LIST( new LocTextKey("sebserver.monitoring.action.list"), PageStateDefinitionImpl.MONITORING_RUNNING_EXAM_LIST), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java index 8692e2b7..5321ffc0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.gui.content.activity; +import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm; +import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm; import ch.ethz.seb.sebserver.gui.content.ExamForm; import ch.ethz.seb.sebserver.gui.content.ExamList; import ch.ethz.seb.sebserver.gui.content.ExamSebConfigMapForm; @@ -67,6 +69,18 @@ public enum PageStateDefinitionImpl implements PageStateDefinition { SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_EDIT(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG), + SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class, ActivityDefinition.SEB_EXAM_CONFIG), + SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class, ActivityDefinition.SEB_EXAM_CONFIG), + + SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_VIEW( + Type.FORM_VIEW, + ConfigTemplateAttributeForm.class, + ActivityDefinition.SEB_EXAM_CONFIG), + SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT( + Type.FORM_EDIT, + ConfigTemplateAttributeForm.class, + ActivityDefinition.SEB_EXAM_CONFIG), + MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java index 42428f77..6b5f589e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java @@ -27,6 +27,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.API; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType; import ch.ethz.seb.sebserver.gbl.model.Entity; @@ -40,6 +41,7 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; 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.View; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType; @@ -58,6 +60,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamNames import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExams; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetupNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViews; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; @@ -465,6 +468,23 @@ public class ResourceService { .collect(Collectors.toList()); } + public List> getViewResources() { + return getViewResources(API.DEFAULT_CONFIG_TEMPLATE_ID); + } + + public List> getViewResources(final String templateId) { + return this.restService.getBuilder(GetViews.class) + .withQueryParam( + View.FILTER_ATTR_TEMPLATE, + templateId) + .call() + .getOr(Collections.emptyList()) + .stream() + .map(view -> new Tuple<>(view.getModelId(), view.name)) + .sorted(RESOURCE_COMPARATOR) + .collect(Collectors.toList()); + } + public Map getExamNameMapping() { final UserInfo userInfo = this.currentUser.get(); return this.restService.getBuilder(GetExamNames.class) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetTemplateAttributePage.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetTemplateAttributePage.java new file mode 100644 index 00000000..ebf92b9f --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetTemplateAttributePage.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 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.Page; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetTemplateAttributePage extends RestCall> { + + public GetTemplateAttributePage() { + super(new TypeKey<>( + CallType.GET_PAGE, + EntityType.CONFIGURATION_NODE, + new TypeReference>() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CONFIGURATION_NODE_ENDPOINT + + API.MODEL_ID_VAR_PATH_SEGMENT + + API.TEMPLATE_ATTRIBUTE_ENDPOINT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViewPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViewPage.java new file mode 100644 index 00000000..6a243f4e --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViewPage.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 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.Page; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetViewPage extends RestCall> { + + public GetViewPage() { + super(new TypeKey<>( + CallType.GET_PAGE, + EntityType.VIEW, + new TypeReference>() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.VIEW_ENDPOINT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViews.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViews.java new file mode 100644 index 00000000..abcfc8fc --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/GetViews.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 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 java.util.List; + +import org.springframework.context.annotation.Lazy; +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.View; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.PageToListCallAdapter; + +@Lazy +@Component +@GuiProfile +public class GetViews extends PageToListCallAdapter { + + public GetViews() { + super( + GetViewPage.class, + EntityType.VIEW, + new TypeReference>() { + }, + API.VIEW_ENDPOINT); + } + +} 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 635a28cf..ed2032b8 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 @@ -36,6 +36,7 @@ import org.eclipse.swt.widgets.Widget; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.MultiValueMap; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.model.Entity; @@ -78,6 +79,7 @@ public class EntityTable { private final TableFilter filter; private final Table table; private final TableNavigator navigator; + private final MultiValueMap staticQueryParams; int pageNumber = 1; int pageSize; @@ -96,7 +98,8 @@ public class EntityTable { final int pageSize, final LocTextKey emptyMessage, final Function, PageAction> defaultActionFunction, - final boolean hideNavigation) { + final boolean hideNavigation, + final MultiValueMap staticQueryParams) { this.composite = new Composite(pageContext.getParent(), type); this.pageService = pageService; @@ -116,6 +119,7 @@ public class EntityTable { this.composite.setLayout(layout); GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); this.composite.setLayoutData(gridData); + this.staticQueryParams = staticQueryParams; // TODO just for debugging, remove when tested // this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0))); @@ -375,6 +379,7 @@ public class EntityTable { .withPaging(pageNumber, pageSize) .withSorting(sortColumn, sortOrder) .withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null) + .withQueryParams(this.staticQueryParams) .apply(this.restCallAdapter) .call() .map(this::createTableRowsFromPage) @@ -494,7 +499,8 @@ public class EntityTable { item.setText(index, this.i18nSupport.formatDisplayDate((DateTime) value)); } else { if (value != null) { - item.setText(index, String.valueOf(value)); + final String val = String.valueOf(value).replace('\n', ' '); + item.setText(index, val); } else { item.setText(index, Constants.EMPTY_NOTE); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java index 4a118380..8b67be02 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java @@ -15,6 +15,8 @@ import java.util.function.Function; import java.util.function.Supplier; import org.eclipse.swt.SWT; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Page; @@ -28,6 +30,7 @@ public class TableBuilder { private final PageService pageService; final RestCall> restCall; + private final MultiValueMap staticQueryParams; final List> columns = new ArrayList<>(); LocTextKey emptyMessage; private Function, PageAction> defaultActionFunction; @@ -42,6 +45,7 @@ public class TableBuilder { this.pageService = pageService; this.restCall = restCall; + this.staticQueryParams = new LinkedMultiValueMap<>(); } public TableBuilder hideNavigation() { @@ -85,6 +89,11 @@ public class TableBuilder { return this; } + public TableBuilder withStaticFilter(final String name, final String value) { + this.staticQueryParams.add(name, value); + return this; + } + public TableBuilder withDefaultActionIf( final BooleanSupplier condition, final Supplier actionSupplier) { @@ -128,7 +137,8 @@ public class TableBuilder { this.pageSize, this.emptyMessage, this.defaultActionFunction, - this.hideNavigation); + this.hideNavigation, + this.staticQueryParams); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java index 42ca57ed..e8a750cf 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java @@ -17,7 +17,7 @@ public interface ConfigurationAttributeDAO extends EntityDAO> getAllRootAttributes(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/OrientationDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/OrientationDAO.java index 73f82c4d..f61e9518 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/OrientationDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/OrientationDAO.java @@ -9,17 +9,25 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import java.util.Collection; +import java.util.Map; import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.util.Result; public interface OrientationDAO extends EntityDAO { /** Use this to delete all Orientation of a defined template. - * + * * @param templateId the template identifier (PK) * @return Collection of all EntityKey of Orientations that has been deleted */ Result> deleteAllOfTemplate(Long templateId); + Result copyDefaultOrientationsForTemplate( + ConfigurationNode node, + Map viewMapping); + + Result> getAllOfTemplate(Long templateId); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ViewDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ViewDAO.java index dadff567..07bc0066 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ViewDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ViewDAO.java @@ -8,8 +8,14 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; +import java.util.Map; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; +import ch.ethz.seb.sebserver.gbl.util.Result; public interface ViewDAO extends EntityDAO { + Result> copyDefaultViewsForTemplate(ConfigurationNode node); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java index 58cf3d35..c1e326c4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationNodeDAOImpl.java @@ -113,10 +113,10 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO { SqlBuilder.isEqualToWhenPresent(filterMap.getInstitutionId())) .and( ConfigurationNodeRecordDynamicSqlSupport.name, - SqlBuilder.isEqualToWhenPresent(filterMap.getName())) + SqlBuilder.isLikeWhenPresent(filterMap.getName())) .and( ConfigurationNodeRecordDynamicSqlSupport.description, - SqlBuilder.isEqualToWhenPresent(filterMap.getConfigNodeDesc())) + SqlBuilder.isLikeWhenPresent(filterMap.getConfigNodeDesc())) .and( ConfigurationNodeRecordDynamicSqlSupport.type, SqlBuilder.isEqualToWhenPresent(filterMap.getConfigNodeType())) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java index 25125a5e..417d2b3f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java @@ -105,7 +105,7 @@ public class InstitutionDAOImpl implements InstitutionDAO { SqlBuilder.isEqualToWhenPresent(filterMap.getActiveAsInt())) .and( InstitutionRecordDynamicSqlSupport.name, - SqlBuilder.isEqualToWhenPresent(filterMap.getName())) + SqlBuilder.isLikeWhenPresent(filterMap.getName())) .build() .execute() .stream() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/OrientationDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/OrientationDAOImpl.java index bef328d6..d535c144 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/OrientationDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/OrientationDAOImpl.java @@ -14,6 +14,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isIn; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -25,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -151,6 +153,55 @@ public class OrientationDAOImpl implements OrientationDAO { .onError(TransactionHandler::rollback); } + @Override + @Transactional + public Result copyDefaultOrientationsForTemplate( + final ConfigurationNode node, + final Map viewMapping) { + + return Result.tryCatch(() -> { + this.orientationRecordMapper + .selectByExample() + .where( + OrientationRecordDynamicSqlSupport.templateId, + SqlBuilder.isEqualTo(ConfigurationNode.DEFAULT_TEMPLATE_ID)) + .build() + .execute() + .stream() + .forEach(record -> createNew(new Orientation( + null, + record.getConfigAttributeId(), + node.id, + viewMapping.get(record.getViewId()), + record.getGroupId(), + record.getxPosition(), + record.getyPosition(), + record.getWidth(), + record.getHeight(), + record.getTitle() != null + ? TitleOrientation.valueOf(record.getTitle()) + : TitleOrientation.NONE))); + + return node; + }); + } + + @Override + @Transactional(readOnly = true) + public Result> getAllOfTemplate(final Long templateId) { + return Result.tryCatch(() -> this.orientationRecordMapper + .selectByExample() + .where( + OrientationRecordDynamicSqlSupport.templateId, + SqlBuilder.isEqualToWhenPresent(templateId)) + .build() + .execute() + .stream() + .map(OrientationDAOImpl::toDomainModel) + .flatMap(DAOLoggingSupport::logAndSkipOnError) + .collect(Collectors.toList())); + } + @Override @Transactional public Result> delete(final Set all) { @@ -215,5 +266,4 @@ public class OrientationDAOImpl implements OrientationDAO { record.getHeight(), TitleOrientation.valueOf(record.getTitle()))); } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ViewDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ViewDAOImpl.java index 845da287..3368c47b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ViewDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ViewDAOImpl.java @@ -13,6 +13,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isIn; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -24,9 +25,11 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ViewRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ViewRecordMapper; import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ViewRecord; @@ -85,6 +88,9 @@ public class ViewDAOImpl implements ViewDAO { .where( ViewRecordDynamicSqlSupport.name, SqlBuilder.isEqualToWhenPresent(filterMap.getName())) + .and( + ViewRecordDynamicSqlSupport.templateId, + SqlBuilder.isEqualToWhenPresent(filterMap.getLong(View.FILTER_ATTR_TEMPLATE))) .build() .execute() .stream() @@ -132,6 +138,34 @@ public class ViewDAOImpl implements ViewDAO { .onError(TransactionHandler::rollback); } + @Override + @Transactional + public Result> copyDefaultViewsForTemplate(final ConfigurationNode node) { + return Result.tryCatch(() -> { + // get all default views, copy them with new template_id and save + return this.viewRecordMapper + .selectByExample() + .where( + ViewRecordDynamicSqlSupport.templateId, + SqlBuilder.isEqualTo(ConfigurationNode.DEFAULT_TEMPLATE_ID)) + .build() + .execute() + .stream() + .map(view -> { + final ViewRecord newRecord = new ViewRecord( + null, + view.getName(), + view.getColumns(), + view.getPosition(), + node.id); + this.viewRecordMapper.insert(newRecord); + return new Tuple<>(view.getId(), newRecord.getId()); + }) + .collect(Collectors.toMap(t -> t._1, t -> t._2)); + + }); + } + @Override @Transactional public Result> delete(final Set all) { 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 a6109c23..c5202c57 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 @@ -12,18 +12,25 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.mybatis.dynamic.sql.SqlTable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -34,11 +41,19 @@ import org.springframework.web.bind.annotation.RestController; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; +import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; +import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey; 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.ConfigurationType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; @@ -46,9 +61,13 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.Authorization import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService; +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.ConfigurationNodeDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.OrientationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ViewDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService; import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService; @@ -60,6 +79,9 @@ public class ConfigurationNodeController extends EntityController getTemplateAttributePage( + @PathVariable final Long modelId, + @RequestParam( + name = API.PARAM_INSTITUTION_ID, + required = true, + defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, + @RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber, + @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize, + @RequestParam(name = Page.ATTR_SORT, required = false) final String sort, + @RequestParam final MultiValueMap allRequestParams) { + + // at least current user must have read access for specified entity type within its own institution + checkReadPrivilege(institutionId); + + final FilterMap filterMap = new FilterMap(allRequestParams); + + // if current user has no read access for specified entity type within other institution + // then the current users institutionId is put as a SQL filter criteria attribute to extends query performance + if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) { + filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId)); + } + + final Map orentiations = this.orientationDAO.getAllOfTemplate(modelId) + .getOrThrow() + .stream() + .collect(Collectors.toMap( + o -> o.attributeId, + Function.identity())); + + final List attrs = this.configurationAttributeDAO + .getAllRootAttributes() + .getOrThrow() + .stream() + .map(attr -> new TemplateAttribute(institutionId, modelId, attr, orentiations.get(attr.id))) + .filter(attr -> attr.isNameLike(filterMap.getString(TemplateAttribute.FILTER_ATTR_NAME)) + && attr.isGroupLike(filterMap.getString(TemplateAttribute.FILTER_ATTR_GROUP)) + && attr.isInView(filterMap.getLong(TemplateAttribute.FILTER_ATTR_VIEW))) + .collect(Collectors.toList()); + + if (!StringUtils.isBlank(sort)) { + final String sortBy = PageSortOrder.decode(sort); + final PageSortOrder sortOrder = PageSortOrder.getSortOrder(sort); + if (sortBy.equals(Domain.CONFIGURATION_NODE.ATTR_NAME)) { + Collections.sort(attrs, TemplateAttribute.nameComparator(sortOrder == PageSortOrder.DESCENDING)); + } + } + + final int start = (pageNumber - 1) * pageSize; + int end = start + pageSize; + if (attrs.size() < end) { + end = attrs.size(); + } + + return new Page<>( + attrs.size() / pageSize, + pageNumber, + sort, + attrs.subList(start, end)); + } + + @Override + protected Result validForSave(final ConfigurationNode entity) { + return super.validForSave(entity) + .map(e -> { + final ConfigurationNode existingNode = this.entityDAO.byPK(entity.id) + .getOrThrow(); + if (existingNode.type != entity.type) { + throw new APIConstraintViolationException( + "The Type of ConfigurationNode cannot change after creation"); + } + return e; + }); + } + + @Override + protected Result notifyCreated(final ConfigurationNode entity) { + return super.notifyCreated(entity) + .map(this::createTemplate); + } + + private ConfigurationNode createTemplate(final ConfigurationNode node) { + if (node.type != null && node.type == ConfigurationType.TEMPLATE) { + // create views and orientations for node + return this.viewDAO.copyDefaultViewsForTemplate(node) + .flatMap(viewMapping -> this.orientationDAO.copyDefaultOrientationsForTemplate( + node, + viewMapping)) + .getOrThrow(); + } + return node; + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ViewController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ViewController.java index a4d11daa..b16e3f25 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ViewController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ViewController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; @@ -57,6 +58,11 @@ public class ViewController extends EntityController { return ViewRecordDynamicSqlSupport.viewRecord; } + @Override + protected EntityType getGrantEntityType() { + return EntityType.CONFIGURATION_NODE; + } + @Override protected Result checkCreateAccess(final View entity) { // Skips the entity based grant check diff --git a/src/main/resources/data-demo.sql b/src/main/resources/data-demo.sql index 20df87f8..f3e1b8dd 100644 --- a/src/main/resources/data-demo.sql +++ b/src/main/resources/data-demo.sql @@ -41,17 +41,17 @@ INSERT IGNORE INTO threshold VALUES ; INSERT IGNORE INTO view VALUES - (1, 'general', 4, 1, null), - (2, 'user_interface', 12, 2, null), - (3, 'browser', 12, 3, null), - (4, 'down_upload', 12, 4, null), - (5, 'exam', 12, 5, null), - (6, 'applications', 12, 6, null), - (7, 'resources', 12, 7, null), - (8, 'network', 12, 8, null), - (9, 'security', 12, 9, null), - (10, 'registry', 12, 10, null), - (11, 'hooked_keys', 12, 11, null); + (1, 'general', 4, 1, 0), + (2, 'user_interface', 12, 2, 0), + (3, 'browser', 12, 3, 0), + (4, 'down_upload', 12, 4, 0), + (5, 'exam', 12, 5, 0), + (6, 'applications', 12, 6, 0), + (7, 'resources', 12, 7, 0), + (8, 'network', 12, 8, 0), + (9, 'security', 12, 9, 0), + (10, 'registry', 12, 10, 0), + (11, 'hooked_keys', 12, 11, 0); INSERT IGNORE INTO configuration_attribute VALUES (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null), diff --git a/src/main/resources/data-prod.sql b/src/main/resources/data-prod.sql index 626c3be6..09cf6d0f 100644 --- a/src/main/resources/data-prod.sql +++ b/src/main/resources/data-prod.sql @@ -14,17 +14,17 @@ INSERT IGNORE INTO user_role VALUES ; INSERT IGNORE INTO view VALUES - (1, 'general', 4, 1, null), - (2, 'user_interface', 12, 2, null), - (3, 'browser', 12, 3, null), - (4, 'down_upload', 12, 4, null), - (5, 'exam', 12, 5, null), - (6, 'applications', 12, 6, null), - (7, 'resources', 12, 7, null), - (8, 'network', 12, 8, null), - (9, 'security', 12, 9, null), - (10, 'registry', 12, 10, null), - (11, 'hooked_keys', 12, 11, null); + (1, 'general', 4, 1, 0), + (2, 'user_interface', 12, 2, 0), + (3, 'browser', 12, 3, 0), + (4, 'down_upload', 12, 4, 0), + (5, 'exam', 12, 5, 0), + (6, 'applications', 12, 6, 0), + (7, 'resources', 12, 7, 0), + (8, 'network', 12, 8, 0), + (9, 'security', 12, 9, 0), + (10, 'registry', 12, 10, 0), + (11, 'hooked_keys', 12, 11, 0); INSERT IGNORE INTO configuration_attribute VALUES (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null), diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index b8d7b742..1d768c55 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -429,7 +429,7 @@ sebserver.examconfig.list.column.status=Status sebserver.examconfig.list.actions=Selected Configuration sebserver.examconfig.list.empty=There is currently no SEB-Exam configuration available. Please create a new one -sebserver.examconfig.info.pleaseSelect=Please Select an exam configuration first +sebserver.examconfig.info.pleaseSelect=Please select an exam configuration first sebserver.examconfig.list.action.no.modify.privilege=No Access: An Exam Configuration from other institution cannot be modified. sebserver.examconfig.action.list.new=Add Exam Configuration @@ -925,6 +925,38 @@ sebserver.examconfig.props.validation.DecimalTypeValidator=Invalid decimal numbe sebserver.examconfig.props.validation.ExitKeySequenceValidator=Key is already in sequence sebserver.examconfig.props.validation.WindowsSizeValidator=Invalid number +################################ +# SEB Exam Configuration Template +################################ + +sebserver.configtemplate.list.title=Configuration Templates +sebserver.configtemplate.list.empty=There is currently no SEB-Exam configuration template available. Please create a new one +sebserver.configtemplate.list.actions=Selected Template + +sebserver.configtemplate.info.pleaseSelect=Please select an exam configuration template first + +sebserver.exam.configtemplate.action.list.new=New Template +sebserver.configtemplate.action.list.view=View Template +sebserver.configtemplate.action.view=View Template +sebserver.configtemplate.action.list.modify=Edit Template +sebserver.configtemplate.action.modify=Edit Template + +sebserver.configtemplate.form.title.new=New Template +sebserver.configtemplate.form.title=Configuration Template +sebserver.configtemplate.form.name=Name +sebserver.configtemplate.form.description=Description +sebserver.configtemplate.action.save=Save Template + +sebserver.configtemplate.attrs.list.title=Configuration Attributes +sebserver.configtemplate.attrs.list.name=Name +sebserver.configtemplate.attrs.list.view=View +sebserver.configtemplate.attrs.list.group=Group + +sebserver.configtemplate.attr.list.actions=Selected Attribute +sebserver.configtemplate.attr.list.actions.modify=Edit Attribute +sebserver.configtemplate.attr.list.actions.setdefault=Set Default Values +sebserver.configtemplate.attr.list.actions.removeview=Remove View + ################################ # Monitoring diff --git a/src/test/resources/data-test-additional.sql b/src/test/resources/data-test-additional.sql index 1db22d3c..f9108833 100644 --- a/src/test/resources/data-test-additional.sql +++ b/src/test/resources/data-test-additional.sql @@ -22,17 +22,17 @@ INSERT IGNORE INTO threshold VALUES ; INSERT IGNORE INTO view VALUES - (1, 'general', 4, 1, null), - (2, 'user_interface', 12, 2, null), - (3, 'browser', 12, 3, null), - (4, 'down_upload', 12, 4, null), - (5, 'exam', 12, 5, null), - (6, 'applications', 12, 6, null), - (7, 'resources', 12, 7, null), - (8, 'network', 12, 8, null), - (9, 'security', 12, 9, null), - (10, 'registry', 12, 10, null), - (11, 'hooked_keys', 12, 11, null); + (1, 'general', 4, 1, 0), + (2, 'user_interface', 12, 2, 0), + (3, 'browser', 12, 3, 0), + (4, 'down_upload', 12, 4, 0), + (5, 'exam', 12, 5, 0), + (6, 'applications', 12, 6, 0), + (7, 'resources', 12, 7, 0), + (8, 'network', 12, 8, 0), + (9, 'security', 12, 9, 0), + (10, 'registry', 12, 10, 0), + (11, 'hooked_keys', 12, 11, 0); INSERT IGNORE INTO configuration_attribute VALUES (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null),