SEBSERV-44 SEBSERV-45 exam config table implementation
This commit is contained in:
parent
e2b93e5529
commit
8867721a8a
56 changed files with 906 additions and 377 deletions
3
pom.xml
3
pom.xml
|
@ -111,7 +111,8 @@
|
|||
<linkXRef>false</linkXRef>
|
||||
<excludes>
|
||||
<exclude>**/batis/mapper/*.java</exclude>
|
||||
<exclude>**/batis/model/*.java</exclude>
|
||||
<exclude>**/batis/model/*.java</exclude>
|
||||
<exclude name="UselessParentheses"/>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
|
|
@ -71,6 +71,8 @@ public final class API {
|
|||
|
||||
public static final String CONFIGURATION_VALUE_ENDPOINT = "/configuration_value";
|
||||
public static final String CONFIGURATION_TABLE_VALUE_PATH_SEGMENT = "/table";
|
||||
public static final String CONFIGURATION_TABLE_ROW_VALUE_PATH_SEGMENT =
|
||||
CONFIGURATION_TABLE_VALUE_PATH_SEGMENT + "/row";
|
||||
|
||||
public static final String CONFIGURATION_ATTRIBUTE_ENDPOINT = "/configuration_attribute";
|
||||
|
||||
|
|
|
@ -24,11 +24,17 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
/** This class defines API error messages that are created and responded on error and/or exceptional
|
||||
* cases within the web-service. */
|
||||
public class APIMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6858683658311637361L;
|
||||
|
||||
/** An enumeration of error messages defining the error code, the HTTP status for the response
|
||||
* and a short system message. This error message definition can be used to
|
||||
* generate APIMessages for default errors. */
|
||||
public enum ErrorMessage {
|
||||
/** For every unknown or unspecific internal error */
|
||||
GENERIC("0", HttpStatus.INTERNAL_SERVER_ERROR, "Generic error message"),
|
||||
UNAUTHORIZED("1000", HttpStatus.UNAUTHORIZED, "UNAUTHORIZED"),
|
||||
FORBIDDEN("1001", HttpStatus.FORBIDDEN, "FORBIDDEN"),
|
||||
|
@ -89,12 +95,19 @@ public class APIMessage implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/** A specific message code that can be used to identify the type of message */
|
||||
@JsonProperty("messageCode")
|
||||
public final String messageCode;
|
||||
|
||||
/** A short system message that describes the cause */
|
||||
@JsonProperty("systemMessage")
|
||||
public final String systemMessage;
|
||||
|
||||
/** Message details */
|
||||
@JsonProperty("details")
|
||||
public final String details;
|
||||
|
||||
/** A list of additional attributes */
|
||||
@JsonProperty("attributes")
|
||||
public final List<String> attributes;
|
||||
|
||||
|
@ -137,6 +150,11 @@ public class APIMessage implements Serializable {
|
|||
return this.attributes;
|
||||
}
|
||||
|
||||
/** Use this as a conversion from a given FieldError of Spring to a APIMessage
|
||||
* of type field validation.
|
||||
*
|
||||
* @param error FieldError instance
|
||||
* @return converted APIMessage of type field validation */
|
||||
public static final APIMessage fieldValidationError(final FieldError error) {
|
||||
final String[] args = StringUtils.split(error.getDefaultMessage(), ":");
|
||||
return ErrorMessage.FIELD_VALIDATION.of(error.toString(), args);
|
||||
|
@ -165,6 +183,10 @@ public class APIMessage implements Serializable {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
/** This exception can be internal used to wrap a created APIMessage
|
||||
* within an Exception and throw. The Exception will be caught a the
|
||||
* APIExceptionHandler endpoint. The APIMessage will be extracted
|
||||
* and send as response. */
|
||||
public static class APIMessageException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1453431210820677296L;
|
||||
|
@ -196,6 +218,10 @@ public class APIMessage implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/** This is used as a field validation exception that creates a APIMessage of filed
|
||||
* validation. The Exception will be caught a the
|
||||
* APIExceptionHandler endpoint. The APIMessage will be extracted
|
||||
* and send as response. */
|
||||
public static class FieldValidationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3324566460573096815L;
|
||||
|
|
|
@ -46,6 +46,8 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
|||
* @param <T> The of the result of the suppling function */
|
||||
public final class MemoizingCircuitBreaker<T> implements Supplier<Result<T>> {
|
||||
|
||||
// TODO considering invalidation time for memoizing
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MemoizingCircuitBreaker.class);
|
||||
|
||||
private final CircuitBreaker<T> delegate;
|
||||
|
|
|
@ -39,7 +39,7 @@ public enum AttributeType {
|
|||
|
||||
FILE_UPLOAD(BASE64_BINARY),
|
||||
|
||||
/** Table type is a list of composite */
|
||||
/** Table type is a list of a composite of single types */
|
||||
TABLE(COMPOSITE_LIST),
|
||||
;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain.CONFIGURATION_VALUE;
|
|||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class ConfigurationTableValue implements GrantEntity {
|
||||
public final class ConfigurationTableValues implements GrantEntity {
|
||||
|
||||
public static final String ATTR_TABLE_VALUES = "tableValues";
|
||||
|
||||
|
@ -42,7 +42,7 @@ public final class ConfigurationTableValue implements GrantEntity {
|
|||
public final List<TableValue> values;
|
||||
|
||||
@JsonCreator
|
||||
public ConfigurationTableValue(
|
||||
public ConfigurationTableValues(
|
||||
@JsonProperty(CONFIGURATION_VALUE.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(CONFIGURATION_VALUE.ATTR_CONFIGURATION_ID) final Long configurationId,
|
||||
@JsonProperty(CONFIGURATION_VALUE.ATTR_CONFIGURATION_ATTRIBUTE_ID) final Long attributeId,
|
||||
|
@ -88,7 +88,7 @@ public final class ConfigurationTableValue implements GrantEntity {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConfigurationTableValue [institutionId=" + this.institutionId + ", configurationId="
|
||||
return "ConfigurationTableValues [institutionId=" + this.institutionId + ", configurationId="
|
||||
+ this.configurationId
|
||||
+ ", attributeId=" + this.attributeId + ", values=" + this.values + "]";
|
||||
}
|
|
@ -17,7 +17,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
|
@ -65,15 +64,8 @@ public class FormBuilder {
|
|||
this.pageContext = pageContext;
|
||||
this.form = new Form(pageService.getJSONMapper());
|
||||
|
||||
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
|
||||
final GridLayout layout = new GridLayout(rows, true);
|
||||
layout.horizontalSpacing = 10;
|
||||
layout.verticalSpacing = 10;
|
||||
layout.marginBottom = 50;
|
||||
layout.marginLeft = 10;
|
||||
layout.marginTop = 0;
|
||||
this.formParent.setLayout(layout);
|
||||
this.formParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
this.formParent = this.widgetFactory
|
||||
.formGrid(pageContext.getParent(), rows);
|
||||
}
|
||||
|
||||
public FormBuilder readonly(final boolean readonly) {
|
||||
|
|
|
@ -22,6 +22,10 @@ public interface InputField {
|
|||
|
||||
void initValue(Collection<ConfigurationValue> values);
|
||||
|
||||
void initValue(final String value, final Integer listIndex);
|
||||
|
||||
String getValue();
|
||||
|
||||
void showError(String errorMessage);
|
||||
|
||||
void clearError();
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.eclipse.swt.widgets.Label;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.InputFieldBuilderSupplier;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
|
@ -24,6 +25,18 @@ public interface InputFieldBuilder {
|
|||
|
||||
String RES_BUNDLE_KEY_PREFIX = "sebserver.examconfig.attribute.";
|
||||
|
||||
/** Called by the InputFieldBuilderSupplier bean instance on initialization to avoid
|
||||
* circular dependencies.
|
||||
*
|
||||
* This method must not be called from other then InputFieldBuilderSupplier
|
||||
* For default this does nothing and a InputFieldBuilder that uses a reference to
|
||||
* the calling InputFieldBuilderSupplier must override this to get the reference
|
||||
*
|
||||
* @param inputFieldBuilderSupplier reference of InputFieldBuilderSupplier */
|
||||
default void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
// NOOP for default
|
||||
}
|
||||
|
||||
boolean builderFor(
|
||||
ConfigurationAttribute attribute,
|
||||
Orientation orientation);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.gui.service.examconfig;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
|
||||
public interface ValueChangeListener {
|
||||
|
@ -20,6 +20,6 @@ public interface ValueChangeListener {
|
|||
String value,
|
||||
int listIndex);
|
||||
|
||||
void tableChanged(ConfigurationTableValue tableValue);
|
||||
void tableChanged(ConfigurationTableValues tableValue);
|
||||
|
||||
}
|
||||
|
|
|
@ -90,12 +90,14 @@ public abstract class AbstractInputField<T extends Control> implements InputFiel
|
|||
values.stream()
|
||||
.filter(a -> this.attribute.id.equals(a.attributeId))
|
||||
.findFirst()
|
||||
.map(v -> {
|
||||
this.initValue = v.value;
|
||||
this.listIndex = (v.listIndex != null) ? v.listIndex : 0;
|
||||
setValueToControl(this.initValue);
|
||||
return this.initValue;
|
||||
});
|
||||
.ifPresent(v -> initValue(v.value, v.listIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initValue(final String value, final Integer listIndex) {
|
||||
this.initValue = value;
|
||||
this.listIndex = (listIndex != null) ? listIndex : 0;
|
||||
setValueToControl(this.initValue);
|
||||
}
|
||||
|
||||
protected void setDefaultValue() {
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.eclipse.swt.widgets.Composite;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
|
@ -66,7 +67,7 @@ public class CheckBoxBuilder implements InputFieldBuilder {
|
|||
|
||||
return new CheckboxField(
|
||||
attribute,
|
||||
viewContext.attributeMapping.getOrientation(attribute.id),
|
||||
viewContext.getOrientation(attribute.id),
|
||||
checkbox);
|
||||
}
|
||||
|
||||
|
@ -84,6 +85,13 @@ public class CheckBoxBuilder implements InputFieldBuilder {
|
|||
protected void setValueToControl(final String value) {
|
||||
this.control.setSelection(Boolean.valueOf(this.initValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getSelection()
|
||||
? Constants.TRUE_STRING
|
||||
: Constants.FALSE_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
|
@ -31,7 +30,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
|||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
|
@ -51,7 +50,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Ge
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientations;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewList;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValue;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
|
@ -66,20 +65,20 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
private final JSONMapper jsonMapper;
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
private final Collection<InputFieldBuilder> inputFieldBuilder;
|
||||
private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
private final Collection<ValueChangeRule> valueChangeRules;
|
||||
|
||||
protected ExamConfigurationServiceImpl(
|
||||
final RestService restService,
|
||||
final JSONMapper jsonMapper,
|
||||
final WidgetFactory widgetFactory,
|
||||
final Collection<InputFieldBuilder> inputFieldBuilder,
|
||||
final InputFieldBuilderSupplier inputFieldBuilderSupplier,
|
||||
final Collection<ValueChangeRule> valueChangeRules) {
|
||||
|
||||
this.restService = restService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.inputFieldBuilder = Utils.immutableCollectionOf(inputFieldBuilder);
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
this.valueChangeRules = Utils.immutableCollectionOf(valueChangeRules);
|
||||
}
|
||||
|
||||
|
@ -93,11 +92,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilder
|
||||
.stream()
|
||||
.filter(b -> b.builderFor(attribute, orientation))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type));
|
||||
return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute, orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -169,7 +164,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
@Override
|
||||
public Composite createViewGrid(final Composite parent, final ViewContext viewContext) {
|
||||
final Composite composite = new Composite(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(viewContext.columns, true);
|
||||
final GridLayout gridLayout = new GridLayout(viewContext.getColumns(), true);
|
||||
gridLayout.verticalSpacing = 0;
|
||||
composite.setLayout(gridLayout);
|
||||
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
@ -179,7 +174,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
viewContext,
|
||||
this);
|
||||
|
||||
for (final ConfigurationAttribute attribute : viewContext.attributeMapping.getAttributes()) {
|
||||
for (final ConfigurationAttribute attribute : viewContext.getAttributes()) {
|
||||
viewGridBuilder.add(attribute);
|
||||
}
|
||||
|
||||
|
@ -269,8 +264,8 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void tableChanged(final ConfigurationTableValue tableValue) {
|
||||
this.restService.getBuilder(SaveExamConfigTableValue.class)
|
||||
public void tableChanged(final ConfigurationTableValues tableValue) {
|
||||
this.restService.getBuilder(SaveExamConfigTableValues.class)
|
||||
.withBody(tableValue)
|
||||
.call();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class InputFieldBuilderSupplier {
|
||||
|
||||
private final Collection<InputFieldBuilder> inputFieldBuilder;
|
||||
|
||||
protected InputFieldBuilderSupplier(final Collection<InputFieldBuilder> inputFieldBuilder) {
|
||||
this.inputFieldBuilder = inputFieldBuilder;
|
||||
inputFieldBuilder
|
||||
.stream()
|
||||
.forEach(builder -> builder.init(this));
|
||||
}
|
||||
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilder
|
||||
.stream()
|
||||
.filter(b -> b.builderFor(attribute, orientation))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type));
|
||||
}
|
||||
|
||||
}
|
|
@ -55,7 +55,7 @@ public class LabelBuilder implements InputFieldBuilder {
|
|||
|
||||
return new LabelField(
|
||||
attribute,
|
||||
viewContext.attributeMapping.getOrientation(attribute.id),
|
||||
viewContext.getOrientation(attribute.id),
|
||||
label);
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,11 @@ public class LabelBuilder implements InputFieldBuilder {
|
|||
// Does Nothing, Label has no default value
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getText();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
|||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Orientation orientation = viewContext.attributeMapping
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, orientation);
|
||||
|
@ -96,15 +96,7 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
String hashedPWD;
|
||||
try {
|
||||
hashedPWD = hashPassword(pwd);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
log.error("Failed to hash password: ", e);
|
||||
passwordInputField.showError("Failed to hash password");
|
||||
hashedPWD = null;
|
||||
}
|
||||
|
||||
final String hashedPWD = passwordInputField.getValue();
|
||||
if (hashedPWD != null) {
|
||||
passwordInputField.clearError();
|
||||
viewContext.getValueChangeListener().valueChanged(
|
||||
|
@ -122,14 +114,6 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
|||
return passwordInputField;
|
||||
}
|
||||
|
||||
private String hashPassword(final String pwd) throws NoSuchAlgorithmException {
|
||||
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
final byte[] encodedhash = digest.digest(
|
||||
pwd.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return Hex.encodeHexString(encodedhash);
|
||||
}
|
||||
|
||||
static final class PasswordInputField extends AbstractInputField<Text> {
|
||||
|
||||
private final Text confirm;
|
||||
|
@ -154,6 +138,28 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
String hashedPWD;
|
||||
try {
|
||||
hashedPWD = hashPassword(this.control.getText());
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
log.error("Failed to hash password: ", e);
|
||||
showError("Failed to hash password");
|
||||
hashedPWD = null;
|
||||
}
|
||||
|
||||
return hashedPWD;
|
||||
}
|
||||
|
||||
private String hashPassword(final String pwd) throws NoSuchAlgorithmException {
|
||||
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
final byte[] encodedhash = digest.digest(
|
||||
pwd.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return Hex.encodeHexString(encodedhash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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.examconfig.impl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigTableRowValues;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
public class TableContext {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TableContext.class);
|
||||
|
||||
private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final RestService restService;
|
||||
|
||||
public final ConfigurationAttribute attribute;
|
||||
public final Orientation orientation;
|
||||
|
||||
private final List<ConfigurationAttribute> rowAttributes;
|
||||
private final List<ConfigurationAttribute> columnAttributes;
|
||||
private final ViewContext viewContext;
|
||||
|
||||
public TableContext(
|
||||
final InputFieldBuilderSupplier inputFieldBuilderSupplier,
|
||||
final WidgetFactory widgetFactory,
|
||||
final RestService restService,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
this.inputFieldBuilderSupplier = Objects.requireNonNull(inputFieldBuilderSupplier);
|
||||
this.widgetFactory = Objects.requireNonNull(widgetFactory);
|
||||
this.restService = Objects.requireNonNull(restService);
|
||||
this.attribute = Objects.requireNonNull(attribute);
|
||||
this.viewContext = Objects.requireNonNull(viewContext);
|
||||
|
||||
this.orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
|
||||
this.rowAttributes = viewContext.getChildAttributes(attribute.id)
|
||||
.stream()
|
||||
.sorted(rowAttributeComparator(viewContext))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
this.columnAttributes = this.rowAttributes
|
||||
.stream()
|
||||
.filter(attr -> viewContext.getOrientation(attr.id).xPosition > 0)
|
||||
.sorted(columnAttributeComparator(viewContext))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public InputFieldBuilderSupplier getInputFieldBuilderSupplier() {
|
||||
return this.inputFieldBuilderSupplier;
|
||||
}
|
||||
|
||||
public WidgetFactory getWidgetFactory() {
|
||||
return this.widgetFactory;
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttribute() {
|
||||
return this.attribute;
|
||||
}
|
||||
|
||||
public Orientation getOrientation() {
|
||||
return this.orientation;
|
||||
}
|
||||
|
||||
public Orientation getOrientation(final Long attributeId) {
|
||||
return this.viewContext.getOrientation(attributeId);
|
||||
}
|
||||
|
||||
public List<ConfigurationAttribute> getRowAttributes() {
|
||||
return this.rowAttributes;
|
||||
}
|
||||
|
||||
public List<ConfigurationAttribute> getColumnAttributes() {
|
||||
return this.columnAttributes;
|
||||
}
|
||||
|
||||
public ViewContext getViewContext() {
|
||||
return this.viewContext;
|
||||
}
|
||||
|
||||
public ValueChangeListener getValueChangeListener() {
|
||||
return this.viewContext.getValueChangeListener();
|
||||
}
|
||||
|
||||
public Long getInstitutionId() {
|
||||
return this.viewContext.getInstitutionId();
|
||||
}
|
||||
|
||||
public Long getConfigurationId() {
|
||||
return this.viewContext.getConfigurationId();
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttribute(final Long attributeId) {
|
||||
return this.viewContext.getAttribute(attributeId);
|
||||
}
|
||||
|
||||
public void flushInputFields(final Set<Long> attributeIds) {
|
||||
this.viewContext.flushInputFields(attributeIds);
|
||||
}
|
||||
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute2,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute2, orientation);
|
||||
}
|
||||
|
||||
public Map<Long, TableValue> getTableRowValues(final int index) {
|
||||
return this.restService.getBuilder(GetExamConfigTableRowValues.class)
|
||||
.withQueryParam(
|
||||
Domain.CONFIGURATION_VALUE.ATTR_CONFIGURATION_ATTRIBUTE_ID,
|
||||
this.attribute.getModelId())
|
||||
.withQueryParam(
|
||||
Domain.CONFIGURATION_VALUE.ATTR_CONFIGURATION_ID,
|
||||
String.valueOf(this.getConfigurationId()))
|
||||
.withQueryParam(
|
||||
Domain.CONFIGURATION_VALUE.ATTR_LIST_INDEX,
|
||||
String.valueOf(index))
|
||||
.call()
|
||||
.get(
|
||||
error -> log.error("Failed to get table row values: ", error),
|
||||
() -> Collections.emptyList())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
val -> val.attributeId,
|
||||
val -> TableValue.of(val)));
|
||||
}
|
||||
|
||||
public void registerInputField(final InputField inputField) {
|
||||
this.viewContext.registerInputField(inputField);
|
||||
}
|
||||
|
||||
private Comparator<ConfigurationAttribute> rowAttributeComparator(final ViewContext viewContext) {
|
||||
return (a1, a2) -> {
|
||||
try {
|
||||
final Orientation o1 = viewContext.getOrientation(a1.id);
|
||||
final Orientation o2 = viewContext.getOrientation(a2.id);
|
||||
return o1.yPosition.compareTo(o2.yPosition);
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to get Orientations of ConfigurationAttribute to compare: ", e);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Comparator<ConfigurationAttribute> columnAttributeComparator(final ViewContext viewContext) {
|
||||
return (a1, a2) -> {
|
||||
try {
|
||||
final Orientation o1 = viewContext.getOrientation(a1.id);
|
||||
final Orientation o2 = viewContext.getOrientation(a2.id);
|
||||
return o1.xPosition.compareTo(o2.xPosition);
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to get Orientations of ConfigurationAttribute to compare: ", e);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl.table;
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -31,19 +31,18 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AbstractInputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
|
@ -56,12 +55,23 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
|
||||
private static final String ROW_VALUE_KEY = "RowValues";
|
||||
|
||||
private final RestService restService;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
|
||||
public TableFieldBuilder(final WidgetFactory widgetFactory) {
|
||||
protected TableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
this.restService = restService;
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
|
@ -81,31 +91,26 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
final ViewContext viewContext) {
|
||||
|
||||
final I18nSupport i18nSupport = viewContext.getI18nSupport();
|
||||
|
||||
final Orientation orientation = viewContext.attributeMapping
|
||||
.getOrientation(attribute.id);
|
||||
final List<ConfigurationAttribute> childAttributes =
|
||||
viewContext.attributeMapping.childAttributeMapping.get(attribute.id);
|
||||
final List<ConfigurationAttribute> columnAttributes = childAttributes
|
||||
.stream()
|
||||
.filter(attr -> viewContext.attributeMapping.getOrientation(attr.id).xPosition > 0)
|
||||
.sorted((attr1, attr2) -> viewContext.attributeMapping.getOrientation(attr1.id).xPosition.compareTo(
|
||||
viewContext.attributeMapping.getOrientation(attr2.id).xPosition))
|
||||
.collect(Collectors.toList());
|
||||
final TableContext tableContext = new TableContext(
|
||||
this.inputFieldBuilderSupplier,
|
||||
this.widgetFactory,
|
||||
this.restService,
|
||||
attribute,
|
||||
viewContext);
|
||||
|
||||
final Table table = new Table(parent, SWT.NONE | SWT.H_SCROLL);
|
||||
table.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
(orientation != null) ? orientation.width() : 1,
|
||||
(orientation != null) ? orientation.height() : 1);
|
||||
gridData.heightHint = orientation.height * 40;
|
||||
(tableContext.orientation != null) ? tableContext.orientation.width() : 1,
|
||||
(tableContext.orientation != null) ? tableContext.orientation.height() : 1);
|
||||
gridData.heightHint = tableContext.orientation.height * 40;
|
||||
table.setLayoutData(gridData);
|
||||
table.setHeaderVisible(true);
|
||||
table.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||
|
||||
for (final ConfigurationAttribute columnAttribute : columnAttributes) {
|
||||
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
|
||||
final TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
final String text = i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + columnAttribute.name,
|
||||
|
@ -116,13 +121,8 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
}
|
||||
|
||||
final TableInputField tableField = new TableInputField(
|
||||
this.widgetFactory,
|
||||
attribute,
|
||||
orientation,
|
||||
table,
|
||||
childAttributes,
|
||||
columnAttributes,
|
||||
viewContext);
|
||||
tableContext,
|
||||
table);
|
||||
|
||||
TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
column.setImage(ImageIcon.ADD_BOX.getImage(parent.getDisplay()));
|
||||
|
@ -175,31 +175,21 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
|
||||
static final class TableInputField extends AbstractInputField<Table> {
|
||||
|
||||
private final List<ConfigurationAttribute> childAttributes;
|
||||
private final List<ConfigurationAttribute> columnAttributes;
|
||||
private final ViewContext viewContext;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final TableContext tableContext;
|
||||
|
||||
private List<Map<Long, TableValue>> values;
|
||||
|
||||
TableInputField(
|
||||
final WidgetFactory widgetFactory,
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Table control,
|
||||
final List<ConfigurationAttribute> childAttributes,
|
||||
final List<ConfigurationAttribute> columnAttributes,
|
||||
final ViewContext viewContext) {
|
||||
final TableContext tableContext,
|
||||
final Table control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
this.childAttributes = childAttributes;
|
||||
this.columnAttributes = columnAttributes;
|
||||
this.viewContext = viewContext;
|
||||
this.widgetFactory = widgetFactory;
|
||||
super(tableContext.attribute, tableContext.orientation, control, null);
|
||||
this.tableContext = tableContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initValue(final Collection<ConfigurationValue> values) {
|
||||
clearTable();
|
||||
// get all child values as TableValues
|
||||
final List<TableValue> tableValues = values.stream()
|
||||
.filter(this::isChildValue)
|
||||
|
@ -229,22 +219,21 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
|
||||
private boolean isChildValue(final ConfigurationValue value) {
|
||||
return this.attribute.id.equals(
|
||||
this.viewContext.attributeMapping.attributeIdMapping
|
||||
.get(value.attributeId).parentId);
|
||||
this.tableContext.getAttribute(value.attributeId).parentId);
|
||||
}
|
||||
|
||||
private void deleteRow(final int selectionIndex) {
|
||||
this.control.remove(selectionIndex);
|
||||
this.values.remove(selectionIndex);
|
||||
// send new values to web-service
|
||||
this.viewContext.getValueChangeListener()
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
}
|
||||
|
||||
private void addRow() {
|
||||
final int index = this.values.size();
|
||||
// create new values form default values
|
||||
final Map<Long, TableValue> rowValues = this.childAttributes
|
||||
final Map<Long, TableValue> rowValues = this.tableContext.getRowAttributes()
|
||||
.stream()
|
||||
.map(attr -> new TableValue(attr.id, index, attr.defaultValue))
|
||||
.collect(Collectors.toMap(
|
||||
|
@ -254,6 +243,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
this.values.add(rowValues);
|
||||
addTableRow(rowValues);
|
||||
this.control.layout();
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
}
|
||||
|
||||
private void addTableRow(final Map<Long, TableValue> rowValues) {
|
||||
|
@ -278,88 +270,105 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
|
||||
}
|
||||
|
||||
private void applyRowValues(
|
||||
final int rowIndex,
|
||||
final Map<Long, TableValue> rowValues) {
|
||||
|
||||
// set the new values
|
||||
this.values.set(rowIndex, rowValues);
|
||||
// update table row
|
||||
applyTableRowValues(rowIndex);
|
||||
|
||||
}
|
||||
// private void applyRowValues(
|
||||
// final int rowIndex,
|
||||
// final Map<Long, TableValue> rowValues) {
|
||||
//
|
||||
// // set the new values
|
||||
// this.values.set(rowIndex, rowValues);
|
||||
// // update table row
|
||||
// applyTableRowValues(rowIndex);
|
||||
//
|
||||
// }
|
||||
|
||||
private void applyTableRowValues(final int index) {
|
||||
final TableItem item = this.control.getItem(index);
|
||||
final Map<Long, TableValue> rowValues = this.values.get(index);
|
||||
|
||||
int cellIndex = 0;
|
||||
for (final ConfigurationAttribute attr : this.columnAttributes) {
|
||||
final String value = rowValues.containsKey(attr.id)
|
||||
? rowValues.get(attr.id).value
|
||||
: null;
|
||||
item.setText(cellIndex, value);
|
||||
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) {
|
||||
if (rowValues.containsKey(attr.id)) {
|
||||
item.setText(cellIndex, rowValues.get(attr.id).value);
|
||||
}
|
||||
cellIndex++;
|
||||
}
|
||||
|
||||
item.setData(ROW_VALUE_KEY, item);
|
||||
|
||||
// send new values to web-service
|
||||
this.viewContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
}
|
||||
|
||||
private void openForm(final int selectionIndex) {
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final ModalInputDialog<Map<Long, TableValue>> dialog = new ModalInputDialog<>(
|
||||
this.control.getShell(),
|
||||
this.widgetFactory);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
selectionIndex);
|
||||
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(rowValues);
|
||||
dialog.open(
|
||||
new LocTextKey("Title"),
|
||||
v -> System.out.println("Values Applied"),
|
||||
builder);
|
||||
new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(500)
|
||||
.open(
|
||||
new LocTextKey("Title"),
|
||||
values -> applyFormValues(values, selectionIndex),
|
||||
builder);
|
||||
}
|
||||
|
||||
private ConfigurationTableValue extractTableValue() {
|
||||
private void applyFormValues(final Map<Long, TableValue> values, final int index) {
|
||||
final Map<Long, TableValue> tableRowValues = this.tableContext.getTableRowValues(index);
|
||||
if (tableRowValues == null || tableRowValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.values.remove(index);
|
||||
this.values.add(index, tableRowValues);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
private ConfigurationTableValues extractTableValue() {
|
||||
final List<TableValue> collect = this.values
|
||||
.stream()
|
||||
.flatMap(map -> map.values().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValue(
|
||||
this.viewContext.getInstitutionId(),
|
||||
this.viewContext.getConfigurationId(),
|
||||
return new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
collect);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDefaultValue() {
|
||||
// NOTE this just empty the list for now
|
||||
// TODO do we need default values for lists?
|
||||
clearTable();
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.tableContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
private void clearTable() {
|
||||
this.control.setSelection(-1);
|
||||
if (this.control.getItemCount() > 0) {
|
||||
for (final TableItem item : this.control.getItems()) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.viewContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValue(
|
||||
this.viewContext.getInstitutionId(),
|
||||
this.viewContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> {
|
||||
|
||||
private final TableContext tableContext;
|
||||
private final Map<Long, TableValue> rowValues;
|
||||
private final int listIndex;
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int listIndex) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = listIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Map<Long, TableValue>> compose(final Composite parent) {
|
||||
|
||||
final List<InputField> inputFields = new ArrayList<>();
|
||||
final Composite grid = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.formGrid(parent, 2);
|
||||
|
||||
final GridLayout layout = (GridLayout) grid.getLayout();
|
||||
layout.verticalSpacing = 0;
|
||||
|
||||
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes()) {
|
||||
createLabel(grid, attribute);
|
||||
inputFields.add(createInputField(grid, attribute));
|
||||
}
|
||||
|
||||
// when the pop-up gets closed we have to remove the input fields from the view context
|
||||
grid.addDisposeListener(event -> {
|
||||
this.tableContext.flushInputFields(this.rowValues.keySet());
|
||||
});
|
||||
|
||||
return () -> inputFields.stream()
|
||||
.map(field -> new TableValue(
|
||||
field.getAttribute().id,
|
||||
this.listIndex,
|
||||
field.getValue()))
|
||||
.collect(Collectors.toMap(tv -> tv.attributeId, Function.identity()));
|
||||
}
|
||||
|
||||
private InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
if (attribute.type == AttributeType.TABLE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Table type is currently not supported within a table row form view!");
|
||||
}
|
||||
|
||||
final Orientation orientation = this.tableContext
|
||||
.getOrientation(attribute.id);
|
||||
|
||||
final InputFieldBuilder inputFieldBuilder = this.tableContext
|
||||
.getInputFieldBuilder(attribute, orientation);
|
||||
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
parent,
|
||||
attribute,
|
||||
this.tableContext.getViewContext());
|
||||
|
||||
inputField.initValue(
|
||||
this.rowValues.get(attribute.id).value,
|
||||
this.listIndex);
|
||||
|
||||
// we have to register the input field within the ViewContext to receive error messages
|
||||
this.tableContext.registerInputField(inputField);
|
||||
|
||||
return inputField;
|
||||
}
|
||||
|
||||
private void createLabel(final Composite parent, final ConfigurationAttribute attribute) {
|
||||
final LocTextKey locTextKey = new LocTextKey(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name);
|
||||
final Label label = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.labelLocalized(parent, locTextKey, attribute.name);
|
||||
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, true, false);
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,7 @@ public class TextFieldBuilder implements InputFieldBuilder {
|
|||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Orientation orientation = viewContext.attributeMapping
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, orientation);
|
||||
|
@ -100,6 +100,11 @@ public class TextFieldBuilder implements InputFieldBuilder {
|
|||
protected void setValueToControl(final String value) {
|
||||
this.control.setText(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getText();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,13 +10,13 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||
|
@ -24,11 +24,11 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
|||
|
||||
public final class ViewContext {
|
||||
|
||||
public final Configuration configuration;
|
||||
public final View view;
|
||||
public final int columns, rows;
|
||||
private final Configuration configuration;
|
||||
private final View view;
|
||||
private final int columns, rows;
|
||||
|
||||
public final AttributeMapping attributeMapping;
|
||||
private final AttributeMapping attributeMapping;
|
||||
private final Map<Long, InputField> inputFieldMapping;
|
||||
private final ValueChangeListener valueChangeListener;
|
||||
private final I18nSupport i18nSupport;
|
||||
|
@ -86,9 +86,36 @@ public final class ViewContext {
|
|||
return this.rows;
|
||||
}
|
||||
|
||||
public List<ConfigurationAttribute> getChildAttributes(final ConfigurationAttribute attribute) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
public Configuration getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this.view;
|
||||
}
|
||||
//
|
||||
// public AttributeMapping getAttributeMapping() {
|
||||
// return this.attributeMapping;
|
||||
// }
|
||||
|
||||
public Collection<ConfigurationAttribute> getChildAttributes(final Long id) {
|
||||
return this.attributeMapping.childAttributeMapping.get(id);
|
||||
}
|
||||
|
||||
public Collection<ConfigurationAttribute> getAttributes() {
|
||||
return this.attributeMapping.getAttributes();
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttribute(final Long attributeId) {
|
||||
return this.attributeMapping.getAttribute(attributeId);
|
||||
}
|
||||
|
||||
public Collection<Orientation> getOrientationsOfGroup(final ConfigurationAttribute attribute) {
|
||||
return this.attributeMapping.getOrientationsOfGroup(attribute);
|
||||
}
|
||||
|
||||
public Orientation getOrientation(final Long attributeId) {
|
||||
return this.attributeMapping.getOrientation(attributeId);
|
||||
}
|
||||
|
||||
public ValueChangeListener getValueChangeListener() {
|
||||
|
@ -126,4 +153,16 @@ public final class ViewContext {
|
|||
.forEach(field -> field.initValue(values));
|
||||
}
|
||||
|
||||
/** Removes all registered InputFields with the given attribute ids
|
||||
*
|
||||
* @param values Collection of attribute ids */
|
||||
void flushInputFields(final Collection<Long> values) {
|
||||
if (values == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.stream()
|
||||
.forEach(attrId -> this.inputFieldMapping.remove(attrId));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
|
@ -30,6 +31,7 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
|||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class ViewGridBuilder {
|
||||
|
||||
|
@ -49,7 +51,7 @@ public class ViewGridBuilder {
|
|||
this.examConfigurationService = examConfigurationService;
|
||||
this.parent = parent;
|
||||
this.viewContext = viewContext;
|
||||
this.grid = new CellFieldBuilderAdapter[viewContext.rows][viewContext.columns];
|
||||
this.grid = new CellFieldBuilderAdapter[viewContext.getRows()][viewContext.getColumns()];
|
||||
this.registeredGroups = new HashSet<>();
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,7 @@ public class ViewGridBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
final Orientation orientation = this.viewContext.attributeMapping
|
||||
final Orientation orientation = this.viewContext
|
||||
.getOrientation(attribute.id);
|
||||
|
||||
// create group builder
|
||||
|
@ -101,6 +103,10 @@ public class ViewGridBuilder {
|
|||
}
|
||||
case LEFT: {
|
||||
this.grid[ypos][xpos - 1] = labelBuilder(attribute, orientation);
|
||||
// special case for password, also add confirm label
|
||||
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||
this.grid[ypos + 1][xpos - 1] = passwordConfirmLabel(attribute, orientation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
|
@ -179,10 +185,6 @@ public class ViewGridBuilder {
|
|||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||
return passwordConfirmLabel(attribute, orientation);
|
||||
}
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
|
@ -192,6 +194,7 @@ public class ViewGridBuilder {
|
|||
ViewGridBuilder.this.parent,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name),
|
||||
attribute.name);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
switch (orientation.title) {
|
||||
|
@ -211,6 +214,7 @@ public class ViewGridBuilder {
|
|||
}
|
||||
}
|
||||
label.setLayoutData(gridData);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -232,6 +236,7 @@ public class ViewGridBuilder {
|
|||
label.setAlignment(SWT.LEFT);
|
||||
gridData.verticalIndent = 10;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -254,7 +259,7 @@ public class ViewGridBuilder {
|
|||
this.builder = builder;
|
||||
this.attribute = attribute;
|
||||
this.orientationsOfGroup =
|
||||
builder.viewContext.attributeMapping.getOrientationsOfGroup(attribute);
|
||||
builder.viewContext.getOrientationsOfGroup(attribute);
|
||||
for (final Orientation o : this.orientationsOfGroup) {
|
||||
this.x = (this.x < o.xpos()) ? o.xpos() : this.x;
|
||||
this.x = (this.y < o.ypos()) ? o.ypos() : this.y;
|
||||
|
@ -291,7 +296,7 @@ public class ViewGridBuilder {
|
|||
final Orientation orientation,
|
||||
final InputFieldBuilder inputFieldBuilder) {
|
||||
|
||||
final ConfigurationAttribute attr = this.builder.viewContext.attributeMapping
|
||||
final ConfigurationAttribute attr = this.builder.viewContext
|
||||
.getAttribute(orientation.attributeId);
|
||||
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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.examconfig.impl.table;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue.TableValue;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||
|
||||
public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> {
|
||||
|
||||
private final Map<Long, TableValue> rowValues;
|
||||
|
||||
public TableRowFormBuilder(final Map<Long, TableValue> rowValues) {
|
||||
this.rowValues = rowValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Map<Long, TableValue>> compose(final Composite parent) {
|
||||
final Label test = new Label(parent, SWT.NONE);
|
||||
test.setText("TEST");
|
||||
return () -> null;
|
||||
}
|
||||
|
||||
}
|
|
@ -139,13 +139,10 @@ public class I18nSupportImpl implements I18nSupport {
|
|||
.toString(this.displayDateFormatter);
|
||||
|
||||
final UserInfo userInfo = this.currentUser.get();
|
||||
if (userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
if (userInfo != null && userInfo.timeZone != null) {
|
||||
return dateTimeStringUTC + date
|
||||
.withZone(userInfo.timeZone)
|
||||
.toString(this.timeZoneFormatter);
|
||||
}
|
||||
return dateTimeStringUTC;
|
||||
if (userInfo != null && userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
return dateTimeStringUTC + date
|
||||
.withZone(userInfo.timeZone)
|
||||
.toString(this.timeZoneFormatter);
|
||||
} else {
|
||||
return dateTimeStringUTC;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class ModalInputDialog<T> extends Dialog {
|
|||
new LocTextKey("sebserver.overall.action.close");
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private int dialogWidth = 400;
|
||||
|
||||
public ModalInputDialog(
|
||||
final Shell parent,
|
||||
|
@ -48,6 +49,11 @@ public class ModalInputDialog<T> extends Dialog {
|
|||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
public ModalInputDialog<T> setDialogWidth(final int dialogWidth) {
|
||||
this.dialogWidth = dialogWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void open(
|
||||
final LocTextKey title,
|
||||
final Consumer<T> callback,
|
||||
|
@ -65,6 +71,8 @@ public class ModalInputDialog<T> extends Dialog {
|
|||
main.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
||||
gridData.horizontalSpan = 2;
|
||||
gridData.widthHint = this.dialogWidth;
|
||||
|
||||
main.setLayoutData(gridData);
|
||||
|
||||
final Supplier<T> valueSuppier = contentComposer.compose(main);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.Collection;
|
||||
|
||||
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.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetExamConfigTableRowValues extends RestCall<Collection<ConfigurationValue>> {
|
||||
|
||||
protected GetExamConfigTableRowValues() {
|
||||
super(new TypeKey<>(
|
||||
CallType.GET_LIST,
|
||||
EntityType.CONFIGURATION_VALUE,
|
||||
new TypeReference<Collection<ConfigurationValue>>() {
|
||||
}),
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.CONFIGURATION_VALUE_ENDPOINT + API.CONFIGURATION_TABLE_ROW_VALUE_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,20 +17,20 @@ 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.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SaveExamConfigTableValue extends RestCall<ConfigurationTableValue> {
|
||||
public class SaveExamConfigTableValues extends RestCall<ConfigurationTableValues> {
|
||||
|
||||
protected SaveExamConfigTableValue() {
|
||||
protected SaveExamConfigTableValues() {
|
||||
super(new TypeKey<>(
|
||||
CallType.SAVE,
|
||||
EntityType.CONFIGURATION_VALUE,
|
||||
new TypeReference<ConfigurationTableValue>() {
|
||||
new TypeReference<ConfigurationTableValues>() {
|
||||
}),
|
||||
HttpMethod.PUT,
|
||||
MediaType.APPLICATION_JSON_UTF8,
|
|
@ -175,6 +175,19 @@ public class WidgetFactory {
|
|||
return defaultPageLayout;
|
||||
}
|
||||
|
||||
public Composite formGrid(final Composite parent, final int rows) {
|
||||
final Composite grid = new Composite(parent, SWT.NONE);
|
||||
final GridLayout layout = new GridLayout(rows, true);
|
||||
layout.horizontalSpacing = 10;
|
||||
layout.verticalSpacing = 10;
|
||||
layout.marginBottom = 50;
|
||||
layout.marginLeft = 10;
|
||||
layout.marginTop = 0;
|
||||
grid.setLayout(layout);
|
||||
grid.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
return grid;
|
||||
}
|
||||
|
||||
public Button buttonLocalized(final Composite parent, final String locTextKey) {
|
||||
final Button button = new Button(parent, SWT.NONE);
|
||||
this.injectI18n(button, new LocTextKey(locTextKey));
|
||||
|
|
|
@ -12,6 +12,8 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
|||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||
|
||||
/** Permission denied exception that refers to the checked entity type, privilege and
|
||||
* the user identifier of the user that did request the permission */
|
||||
public class PermissionDeniedException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 5333137812363042580L;
|
||||
|
|
|
@ -22,7 +22,10 @@ import org.springframework.util.CollectionUtils;
|
|||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
|
||||
/** SEBServerUser defines web-service internal user-account based authentication principal */
|
||||
/** SEBServerUser defines web-service internal user-account based authentication principal
|
||||
*
|
||||
* This implements Spring's UserDetails and CredentialsContainer to act as a principal
|
||||
* within internal authentication and authorization processes. */
|
||||
public final class SEBServerUser implements UserDetails, CredentialsContainer {
|
||||
|
||||
private static final long serialVersionUID = 5726250141482925769L;
|
||||
|
|
|
@ -108,7 +108,7 @@ public interface BulkActionSupportDAO<T extends Entity> {
|
|||
return bulkAction.sources
|
||||
.stream()
|
||||
.map(selectionFunction) // apply select function for each source key
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip) // handle and skip results with error
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError) // handle and skip results with error
|
||||
.flatMap(Collection::stream) // Flatten stream of Collection in to one stream
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Collection;
|
|||
import java.util.Set;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
|
@ -26,11 +26,17 @@ public interface ConfigurationValueDAO extends EntityDAO<ConfigurationValue, Con
|
|||
"Deletion is not supported for ConfigurationValue. A ConfigurationValue get automatically deleted on deletion of a Configuration");
|
||||
}
|
||||
|
||||
Result<ConfigurationTableValue> getTableValue(
|
||||
Result<ConfigurationTableValues> getTableValues(
|
||||
final Long institutionId,
|
||||
final Long attributeId,
|
||||
final Long configurationId);
|
||||
final Long configurationId,
|
||||
final Long attributeId);
|
||||
|
||||
Result<ConfigurationTableValue> saveTableValue(ConfigurationTableValue value);
|
||||
Result<ConfigurationTableValues> saveTableValues(ConfigurationTableValues value);
|
||||
|
||||
Result<Collection<ConfigurationValue>> getTableRowValues(
|
||||
final Long institutionId,
|
||||
final Long configurationId,
|
||||
final Long attributeId,
|
||||
final Integer rowIndex);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public final class DAOLoggingSupport {
|
|||
|
||||
public static final Logger log = LoggerFactory.getLogger(DAOLoggingSupport.class);
|
||||
|
||||
public static <T> Stream<T> logUnexpectedErrorAndSkip(final Result<T> result) {
|
||||
public static <T> Stream<T> logAndSkipOnError(final Result<T> result) {
|
||||
return Result.skipOnError(
|
||||
result.onError(error -> log.error("Unexpected error. Object processing is skipped: ", error)));
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public final class ResourceNotFoundException extends RuntimeException {
|
|||
|
||||
private static final long serialVersionUID = 8319235723086949618L;
|
||||
|
||||
/** The entity key of the resource that was requested */
|
||||
public final EntityKey entityKey;
|
||||
|
||||
public ResourceNotFoundException(final EntityType entityType, final String modelId) {
|
||||
|
|
|
@ -82,7 +82,7 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationAttributeDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationAttributeDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class ConfigurationDAOImpl implements ConfigurationDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ public class ConfigurationDAOImpl implements ConfigurationDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationNodeDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationNodeDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
@ -362,21 +362,18 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.forEach(attrRec -> {
|
||||
final boolean bigValue = ConfigurationValueDAOImpl.isBigValue(attrRec);
|
||||
final String value = templateValues.getOrDefault(
|
||||
attrRec.getId(),
|
||||
attrRec.getDefaultValue());
|
||||
|
||||
//if (StringUtils.isNoneBlank(value)) {
|
||||
this.configurationValueRecordMapper.insert(new ConfigurationValueRecord(
|
||||
null,
|
||||
configNode.institutionId,
|
||||
config.getId(),
|
||||
attrRec.getId(),
|
||||
0,
|
||||
bigValue ? null : value,
|
||||
bigValue ? value : null));
|
||||
//}
|
||||
value,
|
||||
null));
|
||||
});
|
||||
|
||||
return configNode;
|
||||
|
|
|
@ -13,6 +13,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -27,10 +28,8 @@ import org.springframework.stereotype.Component;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeValueType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
@ -101,7 +100,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationValueDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
@ -116,7 +115,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationValueDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -133,15 +132,14 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
final String value = (data.value != null)
|
||||
? data.value
|
||||
: attributeRecord.getDefaultValue();
|
||||
final boolean bigValue = isBigValue(attributeRecord);
|
||||
final ConfigurationValueRecord newRecord = new ConfigurationValueRecord(
|
||||
null,
|
||||
data.institutionId,
|
||||
data.configurationId,
|
||||
data.attributeId,
|
||||
data.listIndex,
|
||||
(bigValue) ? null : value,
|
||||
(bigValue) ? value : null);
|
||||
value,
|
||||
null);
|
||||
|
||||
this.configurationValueRecordMapper.insert(newRecord);
|
||||
return newRecord;
|
||||
|
@ -178,15 +176,14 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
id = data.id;
|
||||
}
|
||||
|
||||
final boolean bigValue = isBigValue(attributeRecord);
|
||||
final ConfigurationValueRecord newRecord = new ConfigurationValueRecord(
|
||||
id,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
data.listIndex,
|
||||
(bigValue) ? null : data.value,
|
||||
(bigValue) ? data.value : null);
|
||||
data.value,
|
||||
null);
|
||||
|
||||
this.configurationValueRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||
return this.configurationValueRecordMapper.selectByPrimaryKey(id);
|
||||
|
@ -197,28 +194,15 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<ConfigurationTableValue> getTableValue(
|
||||
public Result<ConfigurationTableValues> getTableValues(
|
||||
final Long institutionId,
|
||||
final Long attributeId,
|
||||
final Long configurationId) {
|
||||
final Long configurationId,
|
||||
final Long attributeId) {
|
||||
|
||||
return attributeRecordById(attributeId)
|
||||
.map(attributeRecord -> {
|
||||
|
||||
// get all attributes of the table (columns)
|
||||
final List<ConfigurationAttributeRecord> columnAttributes =
|
||||
this.configurationAttributeRecordMapper.selectByExample()
|
||||
.where(
|
||||
ConfigurationAttributeRecordDynamicSqlSupport.parentId,
|
||||
isEqualTo(attributeRecord.getId()))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
final Map<Long, ConfigurationAttributeRecord> attributeMapping = columnAttributes
|
||||
.stream()
|
||||
.collect(Collectors.toMap(attr -> attr.getId(), Function.identity()));
|
||||
|
||||
// get all values of the table and group them by attribute and sorted by list/row index
|
||||
.flatMap(this::getAttributeMapping)
|
||||
.map(attributeMapping -> {
|
||||
// get all values of the table
|
||||
final List<TableValue> values = this.configurationValueRecordMapper.selectByExample()
|
||||
.where(
|
||||
ConfigurationValueRecordDynamicSqlSupport.institutionId,
|
||||
|
@ -232,10 +216,13 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(value -> getTableValue(value, attributeMapping))
|
||||
.map(value -> new TableValue(
|
||||
value.getConfigurationAttributeId(),
|
||||
value.getListIndex(),
|
||||
value.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValue(
|
||||
return new ConfigurationTableValues(
|
||||
institutionId,
|
||||
configurationId,
|
||||
attributeId,
|
||||
|
@ -243,23 +230,66 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
});
|
||||
}
|
||||
|
||||
private TableValue getTableValue(
|
||||
final ConfigurationValueRecord value,
|
||||
final Map<Long, ConfigurationAttributeRecord> attributeMapping) {
|
||||
@Override
|
||||
public Result<Collection<ConfigurationValue>> getTableRowValues(
|
||||
final Long institutionId,
|
||||
final Long configurationId,
|
||||
final Long attributeId,
|
||||
final Integer rowIndex) {
|
||||
|
||||
final Long configurationAttributeId = value.getConfigurationAttributeId();
|
||||
final ConfigurationAttributeRecord configurationAttributeRecord = attributeMapping
|
||||
.get(configurationAttributeId);
|
||||
final boolean bigValue = isBigValue(configurationAttributeRecord);
|
||||
return new TableValue(
|
||||
value.getConfigurationAttributeId(),
|
||||
value.getListIndex(),
|
||||
bigValue ? value.getText() : value.getValue());
|
||||
return attributeRecordById(attributeId)
|
||||
.flatMap(this::getAttributeMapping)
|
||||
.map(attributeMapping -> {
|
||||
|
||||
if (attributeMapping == null || attributeMapping.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// get all values of the table for specified row
|
||||
return this.configurationValueRecordMapper.selectByExample()
|
||||
.where(
|
||||
ConfigurationValueRecordDynamicSqlSupport.institutionId,
|
||||
isEqualTo(institutionId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationId,
|
||||
isEqualTo(configurationId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.listIndex,
|
||||
isEqualTo(rowIndex))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
|
||||
SqlBuilder.isIn(new ArrayList<>(attributeMapping.keySet())))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(ConfigurationValueDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
// get all attributes of the table (columns) mapped to attribute id
|
||||
private Result<Map<Long, ConfigurationAttributeRecord>> getAttributeMapping(
|
||||
final ConfigurationAttributeRecord attributeRecord) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
final List<ConfigurationAttributeRecord> columnAttributes =
|
||||
this.configurationAttributeRecordMapper.selectByExample()
|
||||
.where(
|
||||
ConfigurationAttributeRecordDynamicSqlSupport.parentId,
|
||||
isEqualTo(attributeRecord.getId()))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
return columnAttributes
|
||||
.stream()
|
||||
.collect(Collectors.toMap(attr -> attr.getId(), Function.identity()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<ConfigurationTableValue> saveTableValue(final ConfigurationTableValue value) {
|
||||
public Result<ConfigurationTableValues> saveTableValues(final ConfigurationTableValues value) {
|
||||
return checkInstitutionalIntegrity(value)
|
||||
.map(this::checkFollowUpIntegrity)
|
||||
.flatMap(val -> attributeRecordById(val.attributeId))
|
||||
|
@ -294,15 +324,14 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
// then add the new values
|
||||
for (final TableValue tableValue : value.values) {
|
||||
final ConfigurationAttributeRecord columnAttr = attributeMap.get(tableValue.attributeId);
|
||||
final boolean bigValue = isBigValue(columnAttr);
|
||||
final ConfigurationValueRecord valueRecord = new ConfigurationValueRecord(
|
||||
null,
|
||||
value.institutionId,
|
||||
value.configurationId,
|
||||
columnAttr.getId(),
|
||||
tableValue.listIndex,
|
||||
(bigValue) ? null : tableValue.value,
|
||||
(bigValue) ? tableValue.value : null);
|
||||
tableValue.value,
|
||||
null);
|
||||
|
||||
this.configurationValueRecordMapper.insert(valueRecord);
|
||||
}
|
||||
|
@ -342,23 +371,16 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
}
|
||||
|
||||
private static Result<ConfigurationValue> toDomainModel(final ConfigurationValueRecord record) {
|
||||
return Result.tryCatch(() -> new ConfigurationValue(
|
||||
record.getId(),
|
||||
record.getInstitutionId(),
|
||||
record.getConfigurationId(),
|
||||
record.getConfigurationAttributeId(),
|
||||
record.getListIndex(),
|
||||
record.getValue()));
|
||||
}
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
public static boolean isBigValue(final ConfigurationAttributeRecord attributeRecord) {
|
||||
try {
|
||||
final AttributeType type = AttributeType.valueOf(attributeRecord.getType());
|
||||
return type.attributeValueType == AttributeValueType.LARGE_TEXT
|
||||
|| type.attributeValueType == AttributeValueType.BASE64_BINARY;
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
return new ConfigurationValue(
|
||||
record.getId(),
|
||||
record.getInstitutionId(),
|
||||
record.getConfigurationId(),
|
||||
record.getConfigurationAttributeId(),
|
||||
record.getListIndex(),
|
||||
record.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
private Result<ConfigurationValue> checkInstitutionalIntegrity(final ConfigurationValue data) {
|
||||
|
@ -371,7 +393,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
});
|
||||
}
|
||||
|
||||
private Result<ConfigurationTableValue> checkInstitutionalIntegrity(final ConfigurationTableValue data) {
|
||||
private Result<ConfigurationTableValues> checkInstitutionalIntegrity(final ConfigurationTableValues data) {
|
||||
return Result.tryCatch(() -> {
|
||||
final ConfigurationRecord r = this.configurationRecordMapper.selectByPrimaryKey(data.configurationId);
|
||||
if (r.getInstitutionId().longValue() != data.institutionId.longValue()) {
|
||||
|
@ -381,7 +403,7 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
});
|
||||
}
|
||||
|
||||
private ConfigurationTableValue checkFollowUpIntegrity(final ConfigurationTableValue data) {
|
||||
private ConfigurationTableValues checkFollowUpIntegrity(final ConfigurationTableValues data) {
|
||||
checkFollowUp(data.configurationId);
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ExamConfigurationMapDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ExamConfigurationMapDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
|
@ -113,7 +113,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
|
||||
return records.stream()
|
||||
.map(InstitutionDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(InstitutionDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(InstitutionDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
|
||||
return records.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
|
@ -266,7 +266,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class OrientationDAOImpl implements OrientationDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(OrientationDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class OrientationDAOImpl implements OrientationDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(OrientationDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class SebClientConfigDAOImpl implements SebClientConfigDAO {
|
|||
|
||||
return records.stream()
|
||||
.map(SebClientConfigDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class SebClientConfigDAOImpl implements SebClientConfigDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(SebClientConfigDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
|
@ -246,7 +246,7 @@ public class SebClientConfigDAOImpl implements SebClientConfigDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(SebClientConfigDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(UserActivityLogDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(UserActivityLogDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(_predicate)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -329,7 +329,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(UserActivityLogDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ public class UserDAOImpl implements UserDAO {
|
|||
|
||||
return records.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public class UserDAOImpl implements UserDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(_predicate)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
|
@ -362,7 +362,7 @@ public class UserDAOImpl implements UserDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class ViewDAOImpl implements ViewDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ViewDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public class ViewDAOImpl implements ViewDAO {
|
|||
.execute()
|
||||
.stream()
|
||||
.map(ViewDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.flatMap(DAOLoggingSupport::logAndSkipOnError)
|
||||
.filter(predicate)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
|
||||
public interface SebExamConfigService {
|
||||
|
||||
void validate(ConfigurationValue value);
|
||||
|
||||
void validate(ConfigurationTableValue tableValue);
|
||||
void validate(ConfigurationTableValues tableValue);
|
||||
|
||||
}
|
||||
|
|
|
@ -9,13 +9,14 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
|
||||
|
@ -27,6 +28,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigServ
|
|||
@WebServiceProfile
|
||||
public class SebExamConfigServiceImpl implements SebExamConfigService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SebExamConfigServiceImpl.class);
|
||||
|
||||
private final ConfigurationAttributeDAO configurationAttributeDAO;
|
||||
private final Collection<ConfigurationValueValidator> validators;
|
||||
|
||||
|
@ -40,7 +43,10 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
|
||||
@Override
|
||||
public void validate(final ConfigurationValue value) {
|
||||
Objects.requireNonNull(value);
|
||||
if (value == null) {
|
||||
log.warn("Validate called with null reference. Ignore this and skip validation");
|
||||
return;
|
||||
}
|
||||
|
||||
final ConfigurationAttribute attribute = this.configurationAttributeDAO.byPK(value.attributeId)
|
||||
.getOrThrow();
|
||||
|
@ -53,7 +59,7 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void validate(final ConfigurationTableValue tableValue) {
|
||||
public void validate(final ConfigurationTableValues tableValue) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
|
|
@ -8,19 +8,21 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
public class IllegalAPIArgumentException extends RuntimeException {
|
||||
/** This exception shall be used on additional validations of API attribute constraints.
|
||||
* Throwing an APIConstraintViolationException will lead to a HTTP 400 Bad Request response. */
|
||||
public class APIConstraintViolationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3732727447520974727L;
|
||||
|
||||
public IllegalAPIArgumentException() {
|
||||
public APIConstraintViolationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IllegalAPIArgumentException(final String message, final Throwable cause) {
|
||||
public APIConstraintViolationException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IllegalAPIArgumentException(final String message) {
|
||||
public APIConstraintViolationException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
@ -111,9 +111,9 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
|
|||
.createErrorResponse(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalAPIArgumentException.class)
|
||||
@ExceptionHandler(APIConstraintViolationException.class)
|
||||
public ResponseEntity<Object> handleIllegalAPIArgumentException(
|
||||
final IllegalAPIArgumentException ex,
|
||||
final APIConstraintViolationException ex,
|
||||
final WebRequest request) {
|
||||
|
||||
log.warn("Illegal API Argument Exception: ", ex);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
@ -24,7 +25,7 @@ import ch.ethz.seb.sebserver.gbl.api.API;
|
|||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
@ -90,7 +91,7 @@ public class ConfigurationValueController extends EntityController<Configuration
|
|||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ConfigurationTableValue getTableValueBy(
|
||||
public ConfigurationTableValues getTableValueBy(
|
||||
@RequestParam(
|
||||
name = Domain.CONFIGURATION_VALUE.ATTR_CONFIGURATION_ATTRIBUTE_ID,
|
||||
required = true) final Long attributeId,
|
||||
|
@ -100,10 +101,36 @@ public class ConfigurationValueController extends EntityController<Configuration
|
|||
|
||||
return this.configurationDAO.byPK(configurationId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(config -> this.configurationValueDAO.getTableValue(
|
||||
.flatMap(config -> this.configurationValueDAO.getTableValues(
|
||||
config.institutionId,
|
||||
configurationId,
|
||||
attributeId))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.CONFIGURATION_TABLE_ROW_VALUE_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public Collection<ConfigurationValue> getTableRowValueBy(
|
||||
@RequestParam(
|
||||
name = Domain.CONFIGURATION_VALUE.ATTR_CONFIGURATION_ATTRIBUTE_ID,
|
||||
required = true) final Long attributeId,
|
||||
@RequestParam(
|
||||
name = Domain.CONFIGURATION_VALUE.ATTR_CONFIGURATION_ID,
|
||||
required = true) final Long configurationId,
|
||||
@RequestParam(
|
||||
name = Domain.CONFIGURATION_VALUE.ATTR_LIST_INDEX,
|
||||
required = true) final Integer rowIndex) {
|
||||
|
||||
return this.configurationDAO.byPK(configurationId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(config -> this.configurationValueDAO.getTableRowValues(
|
||||
config.institutionId,
|
||||
configurationId,
|
||||
attributeId,
|
||||
configurationId))
|
||||
rowIndex))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
|
@ -112,12 +139,12 @@ public class ConfigurationValueController extends EntityController<Configuration
|
|||
method = RequestMethod.PUT,
|
||||
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ConfigurationTableValue savePut(
|
||||
@Valid @RequestBody final ConfigurationTableValue tableValue) {
|
||||
public ConfigurationTableValues savePut(
|
||||
@Valid @RequestBody final ConfigurationTableValues tableValue) {
|
||||
|
||||
return this.configurationDAO.byPK(tableValue.configurationId)
|
||||
.flatMap(this.authorization::checkModify)
|
||||
.flatMap(config -> this.configurationValueDAO.saveTableValue(tableValue))
|
||||
.flatMap(config -> this.configurationValueDAO.saveTableValues(tableValue))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
|
@ -149,7 +176,7 @@ public class ConfigurationValueController extends EntityController<Configuration
|
|||
_entity.attributeId != null &&
|
||||
_entity.listIndex != null;
|
||||
if (!idSet && !idsSet) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
throw new APIConstraintViolationException(
|
||||
"Missing some mandatory attributes. Either id must be set or all of configurationId, attributeId and listIndex");
|
||||
|
||||
}
|
||||
|
|
|
@ -355,7 +355,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return this.beanValidationService.validateBean(entity);
|
||||
} else {
|
||||
return Result.ofError(
|
||||
new IllegalAPIArgumentException("Model identifier already defined: " + entity.getModelId()));
|
||||
new APIConstraintViolationException("Model identifier already defined: " + entity.getModelId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
if (entity.getModelId() != null) {
|
||||
return Result.of(entity);
|
||||
} else {
|
||||
return Result.ofError(new IllegalAPIArgumentException("Missing model identifier"));
|
||||
return Result.ofError(new APIConstraintViolationException("Missing model identifier"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ public class SebClientConfigController extends ActivatableEntityController<SebCl
|
|||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID);
|
||||
|
||||
if (institutionId == null) {
|
||||
throw new IllegalAPIArgumentException("Institution identifier is missing");
|
||||
throw new APIConstraintViolationException("Institution identifier is missing");
|
||||
}
|
||||
|
||||
postParams.putIfAbsent(
|
||||
|
|
|
@ -156,7 +156,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
// check of institution of UserInfo is active. Otherwise save is not valid
|
||||
if (!this.beanValidationService
|
||||
.isActive(new EntityKey(userInfo.getInstitutionId(), EntityType.INSTITUTION))) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
throw new APIConstraintViolationException(
|
||||
"User within an inactive institution cannot be created nor modified");
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
if (userRolesOfAccount.contains(UserRole.SEB_SERVER_ADMIN) &&
|
||||
!rolesOfCurrentUser.contains(UserRole.SEB_SERVER_ADMIN)) {
|
||||
|
||||
throw new IllegalAPIArgumentException(
|
||||
throw new APIConstraintViolationException(
|
||||
"The current user cannot edit a User-Account of heigher role pased rank: "
|
||||
+ UserRole.SEB_SERVER_ADMIN);
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
.orElse(null);
|
||||
|
||||
if (nonePublicRole != null) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
throw new APIConstraintViolationException(
|
||||
"The current user has not the privilege to create a User-Account with none public role: "
|
||||
+ nonePublicRole);
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>sebMode</key>
|
||||
<integer>1</integer>
|
||||
<key>sebServerFallback</key>
|
||||
<true />
|
||||
<key>sebServerURL</key>
|
||||
<string>http://localhost:8080</string>
|
||||
<key>sebServerConfiguration</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>institution</key>
|
||||
<string>1</string>
|
||||
<key>clientName</key>
|
||||
<string>+Ra01]`-4e*$(=@=</string>
|
||||
<key>clientSecret</key>
|
||||
<string>(+8Jl-#l8t(XHi%hxi88HXsjC{BE1F(TgdbQSzz=TpR]%_fJ~IjkdAL^YzfV*()t</string>
|
||||
<key>accessTokenEndpoint</key>
|
||||
<string>/oauth/token</string>
|
||||
<key>handshakeEndpoint</key>
|
||||
<string>/exam-api/v1/handshake</string>
|
||||
<key>examConfigEndpoint</key>
|
||||
<string>/exam-api/v1/examconfig</string>
|
||||
<key>pingEndpoint</key>
|
||||
<string>/exam-api/v1/sebping</string>
|
||||
<key>eventEndpoint</key>
|
||||
<string>/exam-api/v1/sebevent</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
Loading…
Reference in a new issue