SEBSERV-72 back and front-end implementation

This commit is contained in:
anhefti 2019-10-15 16:48:18 +02:00
parent 80effa4fe9
commit b71968628c
29 changed files with 1070 additions and 68 deletions

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gbl.api; package ch.ethz.seb.sebserver.gbl.api;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
public final class API { public final class API {
public enum BulkActionType { public enum BulkActionType {
@ -25,6 +27,7 @@ public final class API {
public static final String PARAM_ENTITY_TYPE = "entityType"; public static final String PARAM_ENTITY_TYPE = "entityType";
public static final String PARAM_BULK_ACTION_TYPE = "bulkActionType"; public static final String PARAM_BULK_ACTION_TYPE = "bulkActionType";
public static final String PARAM_CLIENT_CONFIG_SECRET = "client_config_secret"; 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 INSTITUTION_VAR_PATH_SEGMENT = "/{" + PARAM_INSTITUTION_ID + "}";
public static final String MODEL_ID_VAR_PATH_SEGMENT = "/{" + PARAM_MODEL_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_PASSWORD_ATTR_NAME = "importFilePassword";
public static final String IMPORT_FILE_ATTR_NAME = "importFile"; 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 ORIENTATION_ENDPOINT = "/orientation";
public static final String VIEW_ENDPOINT = ORIENTATION_ENDPOINT + "/view"; public static final String VIEW_ENDPOINT = ORIENTATION_ENDPOINT + "/view";

View file

@ -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<TemplateAttribute> nameComparator(final boolean descending) {
return (attr1, attr2) -> attr1.configAttribute.name.compareToIgnoreCase(
attr2.configAttribute.name) * ((descending) ? -1 : 1);
}
}

View file

@ -22,6 +22,8 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class View implements Entity { public class View implements Entity {
public static final String FILTER_ATTR_TEMPLATE = "templateId";
@JsonProperty(VIEW.ATTR_ID) @JsonProperty(VIEW.ATTR_ID)
public final Long id; public final Long id;

View file

@ -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
}
}

View file

@ -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<ConfigurationNode> 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<TemplateAttribute> 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<TemplateAttribute, String> getViewNameFunction(final EntityKey templateId) {
final Map<String, String> mapping = this.resourceService.getViewResources(templateId.modelId)
.stream()
.collect(Collectors.toMap(tuple -> tuple._1, tuple -> tuple._2));
return attr -> mapping.get(attr.getViewModelId());
}
}

View file

@ -9,7 +9,6 @@
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; 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;
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.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; 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.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@ -43,10 +44,14 @@ public class SebExamConfigList implements TemplateComposer {
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege"); 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"); 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"); 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 = private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.institution"); new LocTextKey("sebserver.examconfig.list.column.institution");
private static final LocTextKey NAME_TEXT_KEY = private static final LocTextKey NAME_TEXT_KEY =
@ -57,6 +62,8 @@ public class SebExamConfigList implements TemplateComposer {
new LocTextKey("sebserver.examconfig.list.column.status"); new LocTextKey("sebserver.examconfig.list.column.status");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.info.pleaseSelect"); 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 institutionFilter;
private final TableFilterAttribute nameFilter = private final TableFilterAttribute nameFilter =
@ -67,19 +74,16 @@ public class SebExamConfigList implements TemplateComposer {
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ResourceService resourceService; private final ResourceService resourceService;
private final int pageSize;
protected SebExamConfigList( protected SebExamConfigList(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser) {
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
@ -94,20 +98,24 @@ public class SebExamConfigList implements TemplateComposer {
@Override @Override
public void compose(final PageContext pageContext) { 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(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_CONFIGURATION_TEXT_KEY);
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// table // exam configuration table
final EntityTable<ConfigurationNode> table = final EntityTable<ConfigurationNode> configTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY) .withStaticFilter(
.withPaging(this.pageSize) Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name())
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
.withPaging(6)
.withColumnIf( .withColumnIf(
() -> isSEBAdmin, () -> isSEBAdmin,
() -> new ColumnDefinition<>( () -> new ColumnDefinition<>(
@ -139,27 +147,80 @@ public class SebExamConfigList implements TemplateComposer {
.create()) .create())
.compose(pageContext.copyOf(content)); .compose(pageContext.copyOf(content));
// configuration template table
widgetFactory.label(content, "");
widgetFactory.labelLocalizedTitle(
content,
TITLE_TEMPLATE_TEXT_KEY);
final EntityTable<ConfigurationNode> 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); final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
pageActionBuilder pageActionBuilder
// Exam Configuration actions...
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW) .newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw) .publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) .withSelect(configTable::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent()) .publishIf(() -> configTable.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withSelect( .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) PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent()) .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST)
.withSelect( .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) 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());
} }
} }

View file

@ -113,15 +113,11 @@ public class SebExamConfigPropForm implements TemplateComposer {
final UserInfo user = this.currentUser.get(); final UserInfo user = this.currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null; final boolean isNew = entityKey == null;
// get data or create new. Handle error if happen // get data or create new. Handle error if happen
final ConfigurationNode examConfig = (isNew) final ConfigurationNode examConfig = (isNew)
? ConfigurationNode.createNewExamConfig((parentEntityKey != null) ? ConfigurationNode.createNewExamConfig(user.institutionId)
? Long.valueOf(parentEntityKey.modelId)
: user.institutionId)
: this.restService : this.restService
.getBuilder(GetExamConfigNode.class) .getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)

View file

@ -21,6 +21,8 @@ public enum ActionCategory {
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2), INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1), SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.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), RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.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), LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),

View file

@ -415,6 +415,58 @@ public enum ActionDefinition {
PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT, PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT,
ActionCategory.FORM), 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( RUNNING_EXAM_VIEW_LIST(
new LocTextKey("sebserver.monitoring.action.list"), new LocTextKey("sebserver.monitoring.action.list"),
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM_LIST), PageStateDefinitionImpl.MONITORING_RUNNING_EXAM_LIST),

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.content.activity; 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.ExamForm;
import ch.ethz.seb.sebserver.gui.content.ExamList; import ch.ethz.seb.sebserver.gui.content.ExamList;
import ch.ethz.seb.sebserver.gui.content.ExamSebConfigMapForm; 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_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_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_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS),
MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.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), MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS),

View file

@ -27,6 +27,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType; import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.model.Entity; 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;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; 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.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.ClientConnection.ConnectionStatus;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType; 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.exam.GetExams;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; 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.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.api.useraccount.GetUserAccountNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@ -465,6 +468,23 @@ public class ResourceService {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public List<Tuple<String>> getViewResources() {
return getViewResources(API.DEFAULT_CONFIG_TEMPLATE_ID);
}
public List<Tuple<String>> 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<Long, String> getExamNameMapping() { public Map<Long, String> getExamNameMapping() {
final UserInfo userInfo = this.currentUser.get(); final UserInfo userInfo = this.currentUser.get();
return this.restService.getBuilder(GetExamNames.class) return this.restService.getBuilder(GetExamNames.class)

View file

@ -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<Page<TemplateAttribute>> {
public GetTemplateAttributePage() {
super(new TypeKey<>(
CallType.GET_PAGE,
EntityType.CONFIGURATION_NODE,
new TypeReference<Page<TemplateAttribute>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT
+ API.MODEL_ID_VAR_PATH_SEGMENT
+ API.TEMPLATE_ATTRIBUTE_ENDPOINT);
}
}

View file

@ -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<Page<View>> {
public GetViewPage() {
super(new TypeKey<>(
CallType.GET_PAGE,
EntityType.VIEW,
new TypeReference<Page<View>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.VIEW_ENDPOINT);
}
}

View file

@ -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<View> {
public GetViews() {
super(
GetViewPage.class,
EntityType.VIEW,
new TypeReference<List<View>>() {
},
API.VIEW_ENDPOINT);
}
}

View file

@ -36,6 +36,7 @@ import org.eclipse.swt.widgets.Widget;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
@ -78,6 +79,7 @@ public class EntityTable<ROW extends Entity> {
private final TableFilter<ROW> filter; private final TableFilter<ROW> filter;
private final Table table; private final Table table;
private final TableNavigator navigator; private final TableNavigator navigator;
private final MultiValueMap<String, String> staticQueryParams;
int pageNumber = 1; int pageNumber = 1;
int pageSize; int pageSize;
@ -96,7 +98,8 @@ public class EntityTable<ROW extends Entity> {
final int pageSize, final int pageSize,
final LocTextKey emptyMessage, final LocTextKey emptyMessage,
final Function<EntityTable<ROW>, PageAction> defaultActionFunction, final Function<EntityTable<ROW>, PageAction> defaultActionFunction,
final boolean hideNavigation) { final boolean hideNavigation,
final MultiValueMap<String, String> staticQueryParams) {
this.composite = new Composite(pageContext.getParent(), type); this.composite = new Composite(pageContext.getParent(), type);
this.pageService = pageService; this.pageService = pageService;
@ -116,6 +119,7 @@ public class EntityTable<ROW extends Entity> {
this.composite.setLayout(layout); this.composite.setLayout(layout);
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
this.composite.setLayoutData(gridData); this.composite.setLayoutData(gridData);
this.staticQueryParams = staticQueryParams;
// TODO just for debugging, remove when tested // TODO just for debugging, remove when tested
// this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0))); // this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0)));
@ -375,6 +379,7 @@ public class EntityTable<ROW extends Entity> {
.withPaging(pageNumber, pageSize) .withPaging(pageNumber, pageSize)
.withSorting(sortColumn, sortOrder) .withSorting(sortColumn, sortOrder)
.withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null) .withQueryParams((this.filter != null) ? this.filter.getFilterParameter() : null)
.withQueryParams(this.staticQueryParams)
.apply(this.restCallAdapter) .apply(this.restCallAdapter)
.call() .call()
.map(this::createTableRowsFromPage) .map(this::createTableRowsFromPage)
@ -494,7 +499,8 @@ public class EntityTable<ROW extends Entity> {
item.setText(index, this.i18nSupport.formatDisplayDate((DateTime) value)); item.setText(index, this.i18nSupport.formatDisplayDate((DateTime) value));
} else { } else {
if (value != null) { if (value != null) {
item.setText(index, String.valueOf(value)); final String val = String.valueOf(value).replace('\n', ' ');
item.setText(index, val);
} else { } else {
item.setText(index, Constants.EMPTY_NOTE); item.setText(index, Constants.EMPTY_NOTE);
} }

View file

@ -15,6 +15,8 @@ import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.eclipse.swt.SWT; 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.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
@ -28,6 +30,7 @@ public class TableBuilder<ROW extends Entity> {
private final PageService pageService; private final PageService pageService;
final RestCall<Page<ROW>> restCall; final RestCall<Page<ROW>> restCall;
private final MultiValueMap<String, String> staticQueryParams;
final List<ColumnDefinition<ROW>> columns = new ArrayList<>(); final List<ColumnDefinition<ROW>> columns = new ArrayList<>();
LocTextKey emptyMessage; LocTextKey emptyMessage;
private Function<EntityTable<ROW>, PageAction> defaultActionFunction; private Function<EntityTable<ROW>, PageAction> defaultActionFunction;
@ -42,6 +45,7 @@ public class TableBuilder<ROW extends Entity> {
this.pageService = pageService; this.pageService = pageService;
this.restCall = restCall; this.restCall = restCall;
this.staticQueryParams = new LinkedMultiValueMap<>();
} }
public TableBuilder<ROW> hideNavigation() { public TableBuilder<ROW> hideNavigation() {
@ -85,6 +89,11 @@ public class TableBuilder<ROW extends Entity> {
return this; return this;
} }
public TableBuilder<ROW> withStaticFilter(final String name, final String value) {
this.staticQueryParams.add(name, value);
return this;
}
public TableBuilder<ROW> withDefaultActionIf( public TableBuilder<ROW> withDefaultActionIf(
final BooleanSupplier condition, final BooleanSupplier condition,
final Supplier<PageAction> actionSupplier) { final Supplier<PageAction> actionSupplier) {
@ -128,7 +137,8 @@ public class TableBuilder<ROW extends Entity> {
this.pageSize, this.pageSize,
this.emptyMessage, this.emptyMessage,
this.defaultActionFunction, this.defaultActionFunction,
this.hideNavigation); this.hideNavigation,
this.staticQueryParams);
} }
} }

View file

@ -9,8 +9,10 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao; package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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.Orientation;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
@ -22,4 +24,10 @@ public interface OrientationDAO extends EntityDAO<Orientation, Orientation> {
* @return Collection of all EntityKey of Orientations that has been deleted */ * @return Collection of all EntityKey of Orientations that has been deleted */
Result<Collection<EntityKey>> deleteAllOfTemplate(Long templateId); Result<Collection<EntityKey>> deleteAllOfTemplate(Long templateId);
Result<ConfigurationNode> copyDefaultOrientationsForTemplate(
ConfigurationNode node,
Map<Long, Long> viewMapping);
Result<Collection<Orientation>> getAllOfTemplate(Long templateId);
} }

View file

@ -8,8 +8,14 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao; 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.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.util.Result;
public interface ViewDAO extends EntityDAO<View, View> { public interface ViewDAO extends EntityDAO<View, View> {
Result<Map<Long, Long>> copyDefaultViewsForTemplate(ConfigurationNode node);
} }

View file

@ -113,10 +113,10 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
SqlBuilder.isEqualToWhenPresent(filterMap.getInstitutionId())) SqlBuilder.isEqualToWhenPresent(filterMap.getInstitutionId()))
.and( .and(
ConfigurationNodeRecordDynamicSqlSupport.name, ConfigurationNodeRecordDynamicSqlSupport.name,
SqlBuilder.isEqualToWhenPresent(filterMap.getName())) SqlBuilder.isLikeWhenPresent(filterMap.getName()))
.and( .and(
ConfigurationNodeRecordDynamicSqlSupport.description, ConfigurationNodeRecordDynamicSqlSupport.description,
SqlBuilder.isEqualToWhenPresent(filterMap.getConfigNodeDesc())) SqlBuilder.isLikeWhenPresent(filterMap.getConfigNodeDesc()))
.and( .and(
ConfigurationNodeRecordDynamicSqlSupport.type, ConfigurationNodeRecordDynamicSqlSupport.type,
SqlBuilder.isEqualToWhenPresent(filterMap.getConfigNodeType())) SqlBuilder.isEqualToWhenPresent(filterMap.getConfigNodeType()))

View file

@ -105,7 +105,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
SqlBuilder.isEqualToWhenPresent(filterMap.getActiveAsInt())) SqlBuilder.isEqualToWhenPresent(filterMap.getActiveAsInt()))
.and( .and(
InstitutionRecordDynamicSqlSupport.name, InstitutionRecordDynamicSqlSupport.name,
SqlBuilder.isEqualToWhenPresent(filterMap.getName())) SqlBuilder.isLikeWhenPresent(filterMap.getName()))
.build() .build()
.execute() .execute()
.stream() .stream()

View file

@ -14,6 +14,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; 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.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -151,6 +153,55 @@ public class OrientationDAOImpl implements OrientationDAO {
.onError(TransactionHandler::rollback); .onError(TransactionHandler::rollback);
} }
@Override
@Transactional
public Result<ConfigurationNode> copyDefaultOrientationsForTemplate(
final ConfigurationNode node,
final Map<Long, Long> 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<Collection<Orientation>> 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 @Override
@Transactional @Transactional
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) { public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
@ -215,5 +266,4 @@ public class OrientationDAOImpl implements OrientationDAO {
record.getHeight(), record.getHeight(),
TitleOrientation.valueOf(record.getTitle()))); TitleOrientation.valueOf(record.getTitle())));
} }
} }

View file

@ -13,6 +13,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; 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.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; 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.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
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.ViewRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ViewRecordMapper; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ViewRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ViewRecord; import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ViewRecord;
@ -85,6 +88,9 @@ public class ViewDAOImpl implements ViewDAO {
.where( .where(
ViewRecordDynamicSqlSupport.name, ViewRecordDynamicSqlSupport.name,
SqlBuilder.isEqualToWhenPresent(filterMap.getName())) SqlBuilder.isEqualToWhenPresent(filterMap.getName()))
.and(
ViewRecordDynamicSqlSupport.templateId,
SqlBuilder.isEqualToWhenPresent(filterMap.getLong(View.FILTER_ATTR_TEMPLATE)))
.build() .build()
.execute() .execute()
.stream() .stream()
@ -132,6 +138,34 @@ public class ViewDAOImpl implements ViewDAO {
.onError(TransactionHandler::rollback); .onError(TransactionHandler::rollback);
} }
@Override
@Transactional
public Result<Map<Long, Long>> 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 @Override
@Transactional @Transactional
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) { public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {

View file

@ -12,18 +12,25 @@ import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; 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.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.SqlTable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping; 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.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; 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.ConfigKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.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.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; 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.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; 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.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.ConfigurationDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationNodeDAO; 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.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.sebconfig.SebExamConfigService;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService; import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
@ -60,6 +79,9 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
private static final Logger log = LoggerFactory.getLogger(ConfigurationNodeController.class); private static final Logger log = LoggerFactory.getLogger(ConfigurationNodeController.class);
private final ConfigurationDAO configurationDAO; private final ConfigurationDAO configurationDAO;
private final ViewDAO viewDAO;
private final OrientationDAO orientationDAO;
private final ConfigurationAttributeDAO configurationAttributeDAO;
private final SebExamConfigService sebExamConfigService; private final SebExamConfigService sebExamConfigService;
protected ConfigurationNodeController( protected ConfigurationNodeController(
@ -70,6 +92,9 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
final PaginationService paginationService, final PaginationService paginationService,
final BeanValidationService beanValidationService, final BeanValidationService beanValidationService,
final ConfigurationDAO configurationDAO, final ConfigurationDAO configurationDAO,
final ViewDAO viewDAO,
final OrientationDAO orientationDAO,
final ConfigurationAttributeDAO configurationAttributeDAO,
final SebExamConfigService sebExamConfigService) { final SebExamConfigService sebExamConfigService) {
super(authorization, super(authorization,
@ -80,6 +105,9 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
beanValidationService); beanValidationService);
this.configurationDAO = configurationDAO; this.configurationDAO = configurationDAO;
this.viewDAO = viewDAO;
this.orientationDAO = orientationDAO;
this.configurationAttributeDAO = configurationAttributeDAO;
this.sebExamConfigService = sebExamConfigService; this.sebExamConfigService = sebExamConfigService;
} }
@ -206,4 +234,101 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
} }
} }
@RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT + API.TEMPLATE_ATTRIBUTE_ENDPOINT,
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Page<TemplateAttribute> 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<String, String> 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<Long, Orientation> orentiations = this.orientationDAO.getAllOfTemplate(modelId)
.getOrThrow()
.stream()
.collect(Collectors.toMap(
o -> o.attributeId,
Function.identity()));
final List<TemplateAttribute> 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<ConfigurationNode> 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<ConfigurationNode> 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;
}
} }

View file

@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
@ -57,6 +58,11 @@ public class ViewController extends EntityController<View, View> {
return ViewRecordDynamicSqlSupport.viewRecord; return ViewRecordDynamicSqlSupport.viewRecord;
} }
@Override
protected EntityType getGrantEntityType() {
return EntityType.CONFIGURATION_NODE;
}
@Override @Override
protected Result<View> checkCreateAccess(final View entity) { protected Result<View> checkCreateAccess(final View entity) {
// Skips the entity based grant check // Skips the entity based grant check

View file

@ -41,17 +41,17 @@ INSERT IGNORE INTO threshold VALUES
; ;
INSERT IGNORE INTO view VALUES INSERT IGNORE INTO view VALUES
(1, 'general', 4, 1, null), (1, 'general', 4, 1, 0),
(2, 'user_interface', 12, 2, null), (2, 'user_interface', 12, 2, 0),
(3, 'browser', 12, 3, null), (3, 'browser', 12, 3, 0),
(4, 'down_upload', 12, 4, null), (4, 'down_upload', 12, 4, 0),
(5, 'exam', 12, 5, null), (5, 'exam', 12, 5, 0),
(6, 'applications', 12, 6, null), (6, 'applications', 12, 6, 0),
(7, 'resources', 12, 7, null), (7, 'resources', 12, 7, 0),
(8, 'network', 12, 8, null), (8, 'network', 12, 8, 0),
(9, 'security', 12, 9, null), (9, 'security', 12, 9, 0),
(10, 'registry', 12, 10, null), (10, 'registry', 12, 10, 0),
(11, 'hooked_keys', 12, 11, null); (11, 'hooked_keys', 12, 11, 0);
INSERT IGNORE INTO configuration_attribute VALUES INSERT IGNORE INTO configuration_attribute VALUES
(1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null), (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null),

View file

@ -14,17 +14,17 @@ INSERT IGNORE INTO user_role VALUES
; ;
INSERT IGNORE INTO view VALUES INSERT IGNORE INTO view VALUES
(1, 'general', 4, 1, null), (1, 'general', 4, 1, 0),
(2, 'user_interface', 12, 2, null), (2, 'user_interface', 12, 2, 0),
(3, 'browser', 12, 3, null), (3, 'browser', 12, 3, 0),
(4, 'down_upload', 12, 4, null), (4, 'down_upload', 12, 4, 0),
(5, 'exam', 12, 5, null), (5, 'exam', 12, 5, 0),
(6, 'applications', 12, 6, null), (6, 'applications', 12, 6, 0),
(7, 'resources', 12, 7, null), (7, 'resources', 12, 7, 0),
(8, 'network', 12, 8, null), (8, 'network', 12, 8, 0),
(9, 'security', 12, 9, null), (9, 'security', 12, 9, 0),
(10, 'registry', 12, 10, null), (10, 'registry', 12, 10, 0),
(11, 'hooked_keys', 12, 11, null); (11, 'hooked_keys', 12, 11, 0);
INSERT IGNORE INTO configuration_attribute VALUES INSERT IGNORE INTO configuration_attribute VALUES
(1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null), (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null),

View file

@ -429,7 +429,7 @@ sebserver.examconfig.list.column.status=Status
sebserver.examconfig.list.actions=Selected Configuration 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.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.list.action.no.modify.privilege=No Access: An Exam Configuration from other institution cannot be modified.
sebserver.examconfig.action.list.new=Add Exam Configuration 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.ExitKeySequenceValidator=Key is already in sequence
sebserver.examconfig.props.validation.WindowsSizeValidator=Invalid number 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 # Monitoring

View file

@ -22,17 +22,17 @@ INSERT IGNORE INTO threshold VALUES
; ;
INSERT IGNORE INTO view VALUES INSERT IGNORE INTO view VALUES
(1, 'general', 4, 1, null), (1, 'general', 4, 1, 0),
(2, 'user_interface', 12, 2, null), (2, 'user_interface', 12, 2, 0),
(3, 'browser', 12, 3, null), (3, 'browser', 12, 3, 0),
(4, 'down_upload', 12, 4, null), (4, 'down_upload', 12, 4, 0),
(5, 'exam', 12, 5, null), (5, 'exam', 12, 5, 0),
(6, 'applications', 12, 6, null), (6, 'applications', 12, 6, 0),
(7, 'resources', 12, 7, null), (7, 'resources', 12, 7, 0),
(8, 'network', 12, 8, null), (8, 'network', 12, 8, 0),
(9, 'security', 12, 9, null), (9, 'security', 12, 9, 0),
(10, 'registry', 12, 10, null), (10, 'registry', 12, 10, 0),
(11, 'hooked_keys', 12, 11, null); (11, 'hooked_keys', 12, 11, 0);
INSERT IGNORE INTO configuration_attribute VALUES INSERT IGNORE INTO configuration_attribute VALUES
(1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null), (1, 'hashedAdminPassword', 'PASSWORD_FIELD', null, null, null, null, null),