SEBSERV-45 Exam Configuration list and form

This commit is contained in:
anhefti 2019-04-23 12:34:11 +02:00
parent c0f68c1340
commit 5c7bbdb3a3
20 changed files with 731 additions and 19 deletions

View file

@ -156,4 +156,28 @@ public final class ConfigurationNode implements GrantEntity, Activatable {
+ ", active=" + this.active + "]";
}
public static ConfigurationNode createNewExamConfig(final Long institutionId) {
return new ConfigurationNode(
null,
institutionId,
null,
null,
null,
ConfigurationType.EXAM_CONFIG,
null,
false);
}
public static ConfigurationNode createNewTemplate(final Long institutionId) {
return new ConfigurationNode(
null,
institutionId,
null,
null,
null,
ConfigurationType.TEMPLATE,
null,
false);
}
}

View file

@ -140,7 +140,7 @@ public class ExamList implements TemplateComposer {
actionBuilder
.newAction(ActionDefinition.EXAM_IMPORT)
.publishIf(userGrant::im)
.publishIf(userGrant::im) // TODO iw instead of im?
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, emptySelectionTextKey)

View file

@ -97,7 +97,6 @@ public class SebClientConfigList implements TemplateComposer {
public void compose(final PageContext pageContext) {
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
pageContext.getParent(),
TITLE_TEXT_KEY);
@ -150,7 +149,7 @@ public class SebClientConfigList implements TemplateComposer {
pageActionBuilder
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
.publishIf(clientConfigGrant::w)
.publishIf(clientConfigGrant::iw)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
@ -158,7 +157,7 @@ public class SebClientConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> clientConfigGrant.m() && table.hasAnyContent());
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent());
}

View file

@ -0,0 +1,176 @@
/*
* 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.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.ConfigurationType;
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.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.page.impl.PageUtils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ActivateExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.DeactivateExamConfig;
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.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.widget.WidgetFactory;
@Lazy
@Component
@GuiProfile
public class SebExamConfigForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.class);
private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new");
private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.examconfig.form.title");
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.name");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.description");
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
protected SebExamConfigForm(
final PageService pageService,
final RestService restService,
final CurrentUser currentUser) {
this.pageService = pageService;
this.restService = restService;
this.currentUser = currentUser;
}
@Override
public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
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)
: 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. "
+ "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.EXAM_CONFIG.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));
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(() -> writeGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_DEACTIVATE)
.withEntityKey(entityKey)
.withSimpleRestCall(this.restService, DeactivateExamConfig.class)
.withConfirm(PageUtils.confirmDeactivation(examConfig, this.restService))
.publishIf(() -> writeGrant && isReadonly && examConfig.isActive())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_ACTIVATE)
.withEntityKey(entityKey)
.withSimpleRestCall(this.restService, ActivateExamConfig.class)
.publishIf(() -> writeGrant && isReadonly && !examConfig.isActive())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE)
.withEntityKey(entityKey)
.withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_CANCEL_MODIFY)
.withEntityKey(entityKey)
.withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
action,
ActionDefinition.SEB_EXAM_CONFIG_LIST))
.publishIf(() -> !isReadonly);
}
}

View file

@ -8,26 +8,155 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.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.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
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.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodes;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.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;
@Lazy
@Component
@GuiProfile
public class SebExamConfigList implements TemplateComposer {
public SebExamConfigList() {
// TODO Auto-generated constructor stub
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.empty");
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.title");
private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.institution");
private static final LocTextKey NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.name");
private static final LocTextKey DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.description");
private static final LocTextKey ACTIVE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.active");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.info.pleaseSelect");
private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
private final PageService pageService;
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}") final Integer pageSize) {
this.pageService = pageService;
this.restService = restService;
this.currentUser = currentUser;
this.resourceService = pageService.getResourceService();
this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource);
}
@Override
public void compose(final PageContext pageContext) {
// TODO Auto-generated method stub
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
pageContext.getParent(),
TITLE_TEXT_KEY);
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// table
final EntityTable<ConfigurationNode> table =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodes.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize)
.withColumnIf(
() -> isSEBAdmin,
() -> new ColumnDefinition<>(
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
INSTITUTION_TEXT_KEY,
examConfigInstitutionNameFunction(this.resourceService),
this.institutionFilter,
false))
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_NAME,
NAME_TEXT_KEY,
entity -> entity.name,
this.nameFilter,
true))
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
DESCRIPTION_TEXT_KEY,
entity -> entity.description,
this.nameFilter,
true))
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_ACTIVE,
ACTIVE_TEXT_KEY,
entity -> entity.active,
true))
.withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_FROM_LIST)
.create())
.compose(content);
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROPERTIES_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent());
}
private static Function<ConfigurationNode, String> examConfigInstitutionNameFunction(
final ResourceService resourceService) {
return config -> resourceService.getInstitutionNameFunction()
.apply(String.valueOf(config.institutionId));
}
}

View file

@ -0,0 +1,33 @@
/*
* 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.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
@Lazy
@Component
@GuiProfile
public class SebExamConfigPropertiesForm implements TemplateComposer {
public SebExamConfigPropertiesForm() {
// TODO Auto-generated constructor stub
}
@Override
public void compose(final PageContext pageContext) {
// TODO Auto-generated method stub
}
}

View file

@ -304,6 +304,51 @@ public enum ActionDefinition {
SEB_EXAM_CONFIG_LIST(
new LocTextKey("sebserver.examconfig.action.list"),
PageStateDefinition.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_NEW(
new LocTextKey("sebserver.examconfig.action.list.new"),
ImageIcon.NEW,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT),
SEB_EXAM_CONFIG_VIEW_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.view"),
ImageIcon.SHOW,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_MODIFY_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_MODIFY(
new LocTextKey("sebserver.examconfig.action.modify"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.FORM),
SEB_EXAM_CONFIG_CANCEL_MODIFY(
new LocTextKey("sebserver.overall.action.modify.cancel"),
ImageIcon.CANCEL,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_SAVE(
new LocTextKey("sebserver.examconfig.action.save"),
ImageIcon.SAVE,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_ACTIVATE(
new LocTextKey("sebserver.examconfig.action.activate"),
ImageIcon.INACTIVE,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_DEACTIVATE(
new LocTextKey("sebserver.examconfig.action.deactivate"),
ImageIcon.ACTIVE,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_MODIFY_PROPERTIES_FROM_LIST(
new LocTextKey("sebserver.examconfig.properties.action.list.modify"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),
;

View file

@ -18,7 +18,9 @@ import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropertiesForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
@ -53,7 +55,12 @@ public enum PageStateDefinition implements PageState {
SEB_CLIENT_CONFIG_VIEW(Type.FORM_VIEW, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_CLIENT_CONFIG_EDIT(Type.FORM_EDIT, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_EXAM_CONFIG_LIST(Type.LIST_VIEW, SebExamConfigList.class, ActivityDefinition.SEB_EXAM_CONFIG)
SEB_EXAM_CONFIG_LIST(Type.LIST_VIEW, SebExamConfigList.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_EDIT(Type.FORM_EDIT, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROPERTIES_EDIT(Type.FORM_VIEW, SebExamConfigPropertiesForm.class,
ActivityDefinition.SEB_EXAM_CONFIG),
;

View file

@ -0,0 +1,40 @@
/*
* 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.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class ActivateExamConfig extends RestCall<EntityProcessingReport> {
protected ActivateExamConfig() {
super(new TypeKey<>(
CallType.ACTIVATION_ACTIVATE,
EntityType.CONFIGURATION_NODE,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT + API.PATH_VAR_ACTIVE);
}
}

View file

@ -0,0 +1,40 @@
/*
* 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.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class DeactivateExamConfig extends RestCall<EntityProcessingReport> {
protected DeactivateExamConfig() {
super(new TypeKey<>(
CallType.ACTIVATION_DEACTIVATE,
EntityType.CONFIGURATION_NODE,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT + API.PATH_VAR_INACTIVE);
}
}

View file

@ -0,0 +1,40 @@
/*
* 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.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetExamConfigNode extends RestCall<ConfigurationNode> {
protected GetExamConfigNode() {
super(new TypeKey<>(
CallType.GET_SINGLE,
EntityType.CONFIGURATION_NODE,
new TypeReference<ConfigurationNode>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

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.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetExamConfigNodes extends RestCall<Page<ConfigurationNode>> {
protected GetExamConfigNodes() {
super(new TypeKey<>(
CallType.GET_PAGE,
EntityType.CONFIGURATION_NODE,
new TypeReference<Page<ConfigurationNode>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT);
}
}

View file

@ -0,0 +1,40 @@
/*
* 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.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class NewExamConfig extends RestCall<ConfigurationNode> {
protected NewExamConfig() {
super(new TypeKey<>(
CallType.NEW,
EntityType.CONFIGURATION_NODE,
new TypeReference<ConfigurationNode>() {
}),
HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT);
}
}

View file

@ -0,0 +1,40 @@
/*
* 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.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class SaveExamConfig extends RestCall<ConfigurationNode> {
protected SaveExamConfig() {
super(new TypeKey<>(
CallType.SAVE,
EntityType.CONFIGURATION_NODE,
new TypeReference<ConfigurationNode>() {
}),
HttpMethod.PUT,
MediaType.APPLICATION_JSON_UTF8,
API.CONFIGURATION_NODE_ENDPOINT);
}
}

View file

@ -13,6 +13,8 @@ import java.net.UnknownHostException;
import javax.sql.DataSource;
import org.cryptonode.jncryptor.AES256JNCryptor;
import org.cryptonode.jncryptor.JNCryptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -68,4 +70,10 @@ public class WebServiceInit implements ApplicationListener<ApplicationReadyEvent
public TokenStore tokenStore(final DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
@Lazy
@Bean
public JNCryptor jnCryptor() {
return new AES256JNCryptor();
}
}

View file

@ -111,20 +111,25 @@ public class ClientCredentialServiceImpl implements ClientCredentialService {
final CharSequence secret = this.environment
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
return this.decrypt(credentials.accessToken, secret);
}
@Override
public CharSequence encrypt(final CharSequence text) {
final CharSequence secret = this.environment
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
return encrypt(text, secret);
}
@Override
public CharSequence decrypt(final CharSequence text) {
final CharSequence secret = this.environment
.getRequiredProperty(SEBSERVER_WEBSERVICE_INTERNAL_SECRET_KEY);
return decrypt(text, secret);
}

View file

@ -15,7 +15,6 @@ import java.nio.CharBuffer;
import java.util.Collection;
import java.util.UUID;
import org.cryptonode.jncryptor.AES256JNCryptor;
import org.cryptonode.jncryptor.CryptorException;
import org.cryptonode.jncryptor.JNCryptor;
import org.slf4j.Logger;
@ -45,17 +44,17 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
private final InstitutionDAO institutionDAO;
private final SebClientConfigDAO sebClientConfigDAO;
private final ClientCredentialService clientCredentialService;
private final JNCryptor jnCryptor;
private final String httpScheme;
private final String serverAddress;
private final String serverPort;
private final String sebClientAPIEndpoint;
private final JNCryptor cryptor = new AES256JNCryptor();
protected SebClientConfigServiceImpl(
final InstitutionDAO institutionDAO,
final SebClientConfigDAO sebClientConfigDAO,
final ClientCredentialService clientCredentialService,
final JNCryptor jnCryptor,
@Value("${sebserver.webservice.http.scheme}") final String httpScheme,
@Value("${server.address}") final String serverAddress,
@Value("${server.port}") final String serverPort,
@ -64,6 +63,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
this.institutionDAO = institutionDAO;
this.sebClientConfigDAO = sebClientConfigDAO;
this.clientCredentialService = clientCredentialService;
this.jnCryptor = jnCryptor;
this.httpScheme = httpScheme;
this.serverAddress = serverAddress;
this.serverPort = serverPort;
@ -166,11 +166,28 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
private byte[] encode(final byte[] plainTextConfig, final CharSequence secret) {
// TODO format the plainTextConfig for SEB Client encoding format
try {
// TODO do we need salt
return this.cryptor.encryptData(plainTextConfig, CharBuffer.wrap(secret).array());
char[] secretChars;
final CharBuffer secretBuffer = CharBuffer.wrap(secret);
if (secretBuffer.hasArray()) {
secretChars = secretBuffer.array();
} else {
secretChars = new char[secretBuffer.length()];
secretBuffer.get(secretChars);
}
// TODO format the plainTextConfig for SEB Client encoding format
// jnCryptor.encryptData(
// plainTextConfig,
// secret,
// encryptionSalt,
// hmacSalt,
// iv);
return this.jnCryptor.encryptData(
plainTextConfig,
secretChars);
} catch (final CryptorException e) {
log.error("Unexpected error while trying to encrypt SEB Client configuration: ", e);
return plainTextConfig;

View file

@ -14,11 +14,13 @@ import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
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.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationNodeDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@ -48,6 +50,8 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
@Override
protected ConfigurationNode createNew(final POSTMapper postParams) {
final Long institutionId = postParams.getLong(API.PARAM_INSTITUTION_ID);
final SEBServerUser currentUser = this.authorization.getUserService().getCurrentUser();
postParams.putIfAbsent(EXAM.ATTR_OWNER, currentUser.uuid());
return new ConfigurationNode(institutionId, postParams);
}

View file

@ -313,16 +313,16 @@ sebserver.sebconfig.activity.name=SEB Configuration
sebserver.clientconfig.action.list=Client Configuration
sebserver.clientconfig.action.export=Export
sebserver.clientconfig.list.empty=There is currently no SEB Client configuration available. Please create a new one
sebserver.clientconfig.list.empty=There is currently no SEB-Client configuration available. Please create a new one
sebserver.clientconfig.list.title=SEB Client Configurations
sebserver.clientconfig.list.actions=Selected Configuration
sebserver.clientconfig.list.column.institution=Institution
sebserver.clientconfig.list.column.name=Name
sebserver.clientconfig.list.column.date=Date
sebserver.clientconfig.list.column.date=Creation Date
sebserver.clientconfig.list.column.active=Active
sebserver.clientconfig.info.pleaseSelect=Please Select a client configuration first
sebserver.clientconfig.form.title.new=New SEB Client Configuration
sebserver.clientconfig.form.title.new=New Client Configuration
sebserver.clientconfig.form.title=SEB Client Configuration
sebserver.clientconfig.form.name=Name
sebserver.clientconfig.form.date=Creation Date
@ -341,7 +341,29 @@ sebserver.clientconfig.action.deactivate=Deactivate
# SEB Exam Configuration
################################
sebserver.examconfig.action.list=Exam Configuration
sebserver.examconfig.list.title=Exam Configurations
sebserver.examconfig.list.column.institution=Institution
sebserver.examconfig.list.column.name=Name
sebserver.examconfig.list.column.description=Description
sebserver.examconfig.list.column.active=Active
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.action.list.new=New Exam Configuration
sebserver.examconfig.action.list.view=View Configuration
sebserver.examconfig.action.list.modify=Edit Configuration
sebserver.examconfig.action.modify=Edit
sebserver.examconfig.action.save=Save
sebserver.examconfig.action.activate=Activate
sebserver.examconfig.action.deactivate=Deactivate
sebserver.examconfig.form.title.new=New Exam Configuration
sebserver.examconfig.form.title=Exam Configuration
sebserver.examconfig.form.name=Name
sebserver.examconfig.form.description=Description
sebserver.examconfig.properties.action.list.modify=Edit Properties

View file

@ -203,6 +203,7 @@ Text.error {
Text[MULTI] {
padding: 5px 10px 5px 10px;
height=50px;
}
Text[BORDER], Text[MULTI][BORDER] {
@ -221,6 +222,7 @@ Text[BORDER]:disabled, Text[MULTI][BORDER]:disabled, Text[BORDER]:read-only,
box-shadow: none;
}
/* Combo default theme */
Combo, Combo[BORDER] {
font: 12px Verdana, "Lucida Sans", Arial, Helvetica, sans-serif;