SEBSERV-30 IndicatorList
This commit is contained in:
parent
100bf77bd4
commit
7ccacfcb73
40 changed files with 606 additions and 191 deletions
|
@ -36,17 +36,17 @@ public final class Constants {
|
|||
.forPattern(DEFAULT_DATE_TIME_FORMAT)
|
||||
.withZoneUTC();
|
||||
|
||||
/** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */
|
||||
// TODO check if this works with DEFAULT_DATE_TIME_FORMAT
|
||||
@Deprecated
|
||||
public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
||||
.forPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZoneUTC();
|
||||
|
||||
/** Date-Time formatter with milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss.S */
|
||||
@Deprecated
|
||||
public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_MILLIS = DateTimeFormat
|
||||
.forPattern("yyyy-MM-dd HH:mm:ss.S")
|
||||
.withZoneUTC();
|
||||
// /** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */
|
||||
// // TODO check if this works with DEFAULT_DATE_TIME_FORMAT
|
||||
// @Deprecated
|
||||
// public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
||||
// .forPattern("yyyy-MM-dd HH:mm:ss")
|
||||
// .withZoneUTC();
|
||||
//
|
||||
// /** Date-Time formatter with milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss.S */
|
||||
// @Deprecated
|
||||
// public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_MILLIS = DateTimeFormat
|
||||
// .forPattern("yyyy-MM-dd HH:mm:ss.S")
|
||||
// .withZoneUTC();
|
||||
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ public final class Utils {
|
|||
|
||||
public static Result<Long> dateTimeStringToTimestamp(final String startTime) {
|
||||
return Result.tryCatch(() -> {
|
||||
return DateTime.parse(startTime, Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS).getMillis();
|
||||
return DateTime.parse(startTime, Constants.STANDARD_DATE_TIME_FORMATTER).getMillis();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -143,11 +143,7 @@ public final class Utils {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (dateString.contains(".")) {
|
||||
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_MILLIS);
|
||||
} else {
|
||||
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
}
|
||||
return DateTime.parse(dateString, Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
}
|
||||
|
||||
public static Long toMilliSeconds(final String dateString) {
|
||||
|
|
|
@ -42,6 +42,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicator;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam;
|
||||
|
@ -113,6 +114,7 @@ public class ExamForm implements TemplateComposer {
|
|||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey());
|
||||
|
||||
// the default page layout with title
|
||||
final LocTextKey titleKey = new LocTextKey(
|
||||
importFromQuizData
|
||||
|
@ -270,11 +272,13 @@ public class ExamForm implements TemplateComposer {
|
|||
.publishIf(() -> modifyGrant)
|
||||
|
||||
.createAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(indicatorTable::getSelection, Action::applySingleSelection, emptySelectionTextKey)
|
||||
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent())
|
||||
|
||||
.createAction(ActionDefinition.EXAM_INDICATOR_DELETE_FROM_LIST)
|
||||
.withSelect(indicatorTable::getSelection, Action::applySingleSelection, emptySelectionTextKey)
|
||||
.withEntityKey(entityKey)
|
||||
.withSelect(indicatorTable::getSelection, this::deleteSelectedIndicator, emptySelectionTextKey)
|
||||
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent());
|
||||
|
||||
// TODO List of attached SEB Configurations
|
||||
|
@ -283,6 +287,15 @@ public class ExamForm implements TemplateComposer {
|
|||
|
||||
}
|
||||
|
||||
private Action deleteSelectedIndicator(final Action action) {
|
||||
final EntityKey indicatorKey = action.getSingleSelection();
|
||||
this.resourceService.getRestService()
|
||||
.getBuilder(DeleteIndicator.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, indicatorKey.modelId)
|
||||
.call();
|
||||
return action;
|
||||
}
|
||||
|
||||
private Result<Exam> getExistingExam(final EntityKey entityKey, final RestService restService) {
|
||||
return restService.getBuilder(GetExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
|
@ -330,7 +343,7 @@ public class ExamForm implements TemplateComposer {
|
|||
if (importFromQuizData) {
|
||||
final PageContext pageContext = action.pageContext();
|
||||
final Action activityHomeAction = pageContext.createAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST);
|
||||
action.pageContext().publishPageEvent(new ActionEvent(activityHomeAction, false));
|
||||
action.pageContext().firePageEvent(new ActionEvent(activityHomeAction, false));
|
||||
return activityHomeAction;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,12 @@ import ch.ethz.seb.sebserver.gbl.model.Domain;
|
|||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.form.PageFormService;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
|
@ -36,7 +34,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicator;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewIndicator;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveIndicator;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
|
@ -46,9 +43,6 @@ public class IndicatorForm implements TemplateComposer {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(IndicatorForm.class);
|
||||
|
||||
private final static LocTextKey listTitleKey =
|
||||
new LocTextKey("sebserver.exam.indicator.thresholds.list.title");
|
||||
|
||||
private final PageFormService pageFormService;
|
||||
private final ResourceService resourceService;
|
||||
|
||||
|
@ -62,12 +56,8 @@ public class IndicatorForm implements TemplateComposer {
|
|||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
|
||||
|
||||
final UserInfo user = currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
|
@ -134,9 +124,13 @@ public class IndicatorForm implements TemplateComposer {
|
|||
(indicator.type != null) ? indicator.type.name() : null,
|
||||
this.resourceService::indicatorTypeResources))
|
||||
.addField(FormBuilder.colorSelection(
|
||||
Domain.INDICATOR.ATTR_TYPE,
|
||||
Domain.INDICATOR.ATTR_COLOR,
|
||||
"sebserver.exam.indicator.form.color",
|
||||
indicator.defaultColor))
|
||||
.addField(FormBuilder.thresholdList(
|
||||
Domain.THRESHOLD.REFERENCE_NAME,
|
||||
"sebserver.exam.indicator.form.thresholds",
|
||||
indicator.getThresholds()))
|
||||
.buildFor((isNew)
|
||||
? restService.getRestCall(NewIndicator.class)
|
||||
: restService.getRestCall(SaveIndicator.class));
|
||||
|
@ -144,7 +138,7 @@ public class IndicatorForm implements TemplateComposer {
|
|||
// propagate content actions to action-pane
|
||||
formContext.clearEntityKeys()
|
||||
.createAction(ActionDefinition.EXAM_INDICATOR_SAVE)
|
||||
.withParentEntityKey(parentEntityKey)
|
||||
.withEntityKey(parentEntityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ public class InstitutionForm implements TemplateComposer {
|
|||
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
|
|
|
@ -200,6 +200,7 @@ public class LmsSetupForm implements TemplateComposer {
|
|||
.publishIf(() -> writeGrant && readonly && institutionActive && !lmsSetup.isActive())
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.publishIf(() -> !readonly)
|
||||
|
||||
|
|
|
@ -66,13 +66,13 @@ public class LoginPage implements TemplateComposer {
|
|||
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
||||
name.setLayoutData(new GridData(300, -1));
|
||||
name.setAlignment(SWT.BOTTOM);
|
||||
final Text loginName = new Text(loginGroup, SWT.LEFT | SWT.BORDER);
|
||||
final Text loginName = this.widgetFactory.textInput(loginGroup);
|
||||
loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
|
||||
pwd.setLayoutData(gridData);
|
||||
final Text loginPassword = new Text(loginGroup, SWT.LEFT | SWT.PASSWORD | SWT.BORDER);
|
||||
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
|
||||
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
|
||||
final Button button = this.widgetFactory.buttonLocalized(loginGroup, "sebserver.login.login");
|
||||
|
|
|
@ -212,6 +212,7 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final Action postChanges = formHandle.processFormSave(action);
|
||||
if (ownAccount) {
|
||||
|
|
|
@ -175,7 +175,15 @@ public class ActionPane implements TemplateComposer {
|
|||
new ArrayList<>(this.actionTrees.entrySet())
|
||||
.stream()
|
||||
.forEach(entry -> {
|
||||
if (entry.getValue().isDisposed()) {
|
||||
final Control c = entry.getValue();
|
||||
// of tree is already disposed.. remove it
|
||||
if (c.isDisposed()) {
|
||||
this.actionTrees.remove(entry.getKey());
|
||||
}
|
||||
// check access from current thread
|
||||
try {
|
||||
c.getBounds();
|
||||
} catch (final Exception e) {
|
||||
this.actionTrees.remove(entry.getKey());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -162,7 +162,7 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
if (mainPageState.action == null) {
|
||||
mainPageState.action = getActivitySelection(navigation.getItem(0));
|
||||
}
|
||||
pageContext.publishPageEvent(
|
||||
pageContext.firePageEvent(
|
||||
new ActionEvent(mainPageState.action, false));
|
||||
navigation.select(navigation.getItem(0));
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
final Action action = getActivitySelection(treeItem);
|
||||
if (mainPageState.action.definition != action.definition) {
|
||||
mainPageState.action = action;
|
||||
composerCtx.publishPageEvent(
|
||||
composerCtx.firePageEvent(
|
||||
new ActionEvent(action, true));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ package ch.ethz.seb.sebserver.gui.form;
|
|||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
public abstract class FieldBuilder {
|
||||
public abstract class FieldBuilder<T> {
|
||||
int spanLabel = -1;
|
||||
int spanInput = -1;
|
||||
int spanEmptyCell = -1;
|
||||
|
@ -22,55 +22,55 @@ public abstract class FieldBuilder {
|
|||
|
||||
final String name;
|
||||
final String label;
|
||||
final String value;
|
||||
final T value;
|
||||
|
||||
protected FieldBuilder(final String name, final String label, final String value) {
|
||||
protected FieldBuilder(final String name, final String label, final T value) {
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public FieldBuilder withLabelSpan(final int span) {
|
||||
public FieldBuilder<T> withLabelSpan(final int span) {
|
||||
this.spanLabel = span;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder withInputSpan(final int span) {
|
||||
public FieldBuilder<T> withInputSpan(final int span) {
|
||||
this.spanInput = span;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder withEmptyCellSpan(final int span) {
|
||||
public FieldBuilder<T> withEmptyCellSpan(final int span) {
|
||||
this.spanEmptyCell = span;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder withEmptyCellSeparation(final boolean separation) {
|
||||
public FieldBuilder<T> withEmptyCellSeparation(final boolean separation) {
|
||||
this.autoEmptyCellSeparation = separation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder withGroup(final String group) {
|
||||
public FieldBuilder<T> withGroup(final String group) {
|
||||
this.group = group;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder withCondition(final BooleanSupplier condition) {
|
||||
public FieldBuilder<T> withCondition(final BooleanSupplier condition) {
|
||||
this.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder readonly(final boolean readonly) {
|
||||
public FieldBuilder<T> readonly(final boolean readonly) {
|
||||
this.readonly = readonly;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder visibleIf(final boolean visible) {
|
||||
public FieldBuilder<T> visibleIf(final boolean visible) {
|
||||
this.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder readonlyIf(final BooleanSupplier readonly) {
|
||||
public FieldBuilder<T> readonlyIf(final BooleanSupplier readonly) {
|
||||
this.readonly = readonly != null && readonly.getAsBoolean();
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.form;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
@ -30,10 +31,12 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ThresholdList;
|
||||
|
||||
public final class Form implements FormBinding {
|
||||
|
||||
|
@ -69,7 +72,7 @@ public final class Form implements FormBinding {
|
|||
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
|
||||
entry.getValue()
|
||||
.stream()
|
||||
.forEach(ffa -> appendFormUrlEncodedValue(buffer, entry.getKey(), ffa.getValue()));
|
||||
.forEach(ffa -> appendFormUrlEncodedValue(buffer, entry.getKey(), ffa.getStringValue()));
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
|
@ -106,6 +109,10 @@ public final class Form implements FormBinding {
|
|||
this.formFields.add(name, createAccessor(label, field));
|
||||
}
|
||||
|
||||
public void putField(final String name, final Label label, final ThresholdList field) {
|
||||
this.formFields.add(name, createAccessor(label, field));
|
||||
}
|
||||
|
||||
public void putField(
|
||||
final String name,
|
||||
final Label label,
|
||||
|
@ -174,7 +181,7 @@ public final class Form implements FormBinding {
|
|||
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
|
||||
entry.getValue()
|
||||
.stream()
|
||||
.filter(ffa -> StringUtils.isNoneBlank(ffa.getValue()))
|
||||
.filter(ffa -> StringUtils.isNoneBlank(ffa.getStringValue()))
|
||||
.forEach(ffa -> ffa.putJsonValue(entry.getKey(), this.objectRoot));
|
||||
}
|
||||
}
|
||||
|
@ -183,14 +190,12 @@ public final class Form implements FormBinding {
|
|||
//@formatter:off
|
||||
private FormFieldAccessor createAccessor(final Label label, final Label field) {
|
||||
return new FormFieldAccessor(label, field) {
|
||||
@Override public String getValue() { return null; }
|
||||
@Override public void setValue(final String value) { field.setText(value); }
|
||||
@Override public String getStringValue() { return null; }
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor createAccessor(final Label label, final Text text) {
|
||||
return new FormFieldAccessor(label, text) {
|
||||
@Override public String getValue() { return text.getText(); }
|
||||
@Override public void setValue(final String value) { text.setText(value); }
|
||||
@Override public String getStringValue() { return text.getText(); }
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor createAccessor(final Label label, final Selection selection) {
|
||||
|
@ -207,14 +212,30 @@ public final class Form implements FormBinding {
|
|||
final BiConsumer<Tuple<String>, ObjectNode> jsonValueAdapter) {
|
||||
|
||||
return new FormFieldAccessor(label, selection.adaptToControl(), jsonValueAdapter) {
|
||||
@Override public String getValue() { return selection.getSelectionValue(); }
|
||||
@Override public void setValue(final String value) { selection.select(value); }
|
||||
@Override public String getStringValue() { return selection.getSelectionValue(); }
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor createAccessor(final Label label, final ThresholdList thresholdList) {
|
||||
return new FormFieldAccessor(label, thresholdList) {
|
||||
@Override public String getStringValue() {
|
||||
return ThresholdListBuilder
|
||||
.thresholdsToFormURLEncodedStringValue(thresholdList.getThresholds());
|
||||
}
|
||||
@Override
|
||||
public void putJsonValue(final String key, final ObjectNode objectRoot) {
|
||||
final Collection<Threshold> thresholds = thresholdList.getThresholds();
|
||||
if (thresholds == null || thresholds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ArrayNode array = Form.this.jsonMapper.valueToTree(thresholds);
|
||||
objectRoot.putArray(key).addAll(array);
|
||||
}
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor createAccessor(final Label label, final ImageUpload imageUpload) {
|
||||
return new FormFieldAccessor(label, imageUpload) {
|
||||
@Override public String getValue() { return imageUpload.getImageBase64(); }
|
||||
@Override public void setValue(final String value) { imageUpload.setImageBase64(value); }
|
||||
@Override public String getStringValue() { return imageUpload.getImageBase64(); }
|
||||
};
|
||||
}
|
||||
//@formatter:on
|
||||
|
@ -224,23 +245,38 @@ public final class Form implements FormBinding {
|
|||
* Checks first if the value String is a comma separated list. If true, splits values
|
||||
* and adds every value within the same name mapping to the string buffer
|
||||
*/
|
||||
private void appendFormUrlEncodedValue(final StringBuffer buffer, final String name, final String value) {
|
||||
private static void appendFormUrlEncodedValue(final StringBuffer buffer, final String name, final String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] split = StringUtils.split(value, Constants.LIST_SEPARATOR_CHAR);
|
||||
if (split != null) {
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (StringUtils.isNoneBlank(split[i])) {
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
|
||||
}
|
||||
buffer.append(name)
|
||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||
.append(split[i]);
|
||||
}
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (StringUtils.isBlank(split[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
|
||||
}
|
||||
|
||||
// check of the string value is a name-value pair. If true, use the specified name an value
|
||||
// otherwise use the general name given within this method call and
|
||||
if (split[i].contains(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)) {
|
||||
final String[] nameValue = StringUtils.split(split[i], Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR);
|
||||
buffer.append(nameValue[0])
|
||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||
.append(nameValue[1]);
|
||||
} else {
|
||||
buffer.append(name)
|
||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||
.append(split[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void adaptCommaSeparatedStringToJsonArray(final Tuple<String> tuple,
|
||||
private static final void adaptCommaSeparatedStringToJsonArray(
|
||||
final Tuple<String> tuple,
|
||||
final ObjectNode jsonNode) {
|
||||
if (StringUtils.isNoneBlank(tuple._2)) {
|
||||
final ArrayNode arrayNode = jsonNode.putArray(tuple._1);
|
||||
|
@ -280,17 +316,15 @@ public final class Form implements FormBinding {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract String getValue();
|
||||
|
||||
public abstract void setValue(String value);
|
||||
public abstract String getStringValue();
|
||||
|
||||
public void setVisible(final boolean visible) {
|
||||
this.label.setVisible(visible);
|
||||
this.control.setVisible(visible);
|
||||
}
|
||||
|
||||
public final void putJsonValue(final String key, final ObjectNode objectRoot) {
|
||||
this.jsonValueAdapter.accept(new Tuple<>(key, getValue()), objectRoot);
|
||||
public void putJsonValue(final String key, final ObjectNode objectRoot) {
|
||||
this.jsonValueAdapter.accept(new Tuple<>(key, getStringValue()), objectRoot);
|
||||
}
|
||||
|
||||
public void setError(final String errorTooltip) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.form;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -26,6 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
|
@ -39,6 +41,7 @@ public class FormBuilder {
|
|||
private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
|
||||
|
||||
final WidgetFactory widgetFactory;
|
||||
final JSONMapper jsonMapper;
|
||||
private final PolyglotPageService polyglotPageService;
|
||||
public final PageContext pageContext;
|
||||
public final Composite formParent;
|
||||
|
@ -58,6 +61,7 @@ public class FormBuilder {
|
|||
final int rows) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
this.pageContext = pageContext;
|
||||
this.form = new Form(jsonMapper);
|
||||
|
@ -145,7 +149,7 @@ public class FormBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder addField(final FieldBuilder template) {
|
||||
public FormBuilder addField(final FieldBuilder<?> template) {
|
||||
if (template.condition == null || template.condition.getAsBoolean()) {
|
||||
template.spanLabel = (template.spanLabel < 0) ? this.defaultSpanLabel : template.spanLabel;
|
||||
template.spanInput = (template.spanInput < 0) ? this.defaultSpanInput : template.spanInput;
|
||||
|
@ -224,6 +228,14 @@ public class FormBuilder {
|
|||
return new SelectionFieldBuilder(Selection.Type.COLOR, name, label, value, null);
|
||||
}
|
||||
|
||||
public static ThresholdListBuilder thresholdList(
|
||||
final String name,
|
||||
final String label,
|
||||
final Collection<Threshold> value) {
|
||||
|
||||
return new ThresholdListBuilder(name, label, value);
|
||||
}
|
||||
|
||||
public static ImageUploadFieldBuilder imageUpload(final String name, final String label, final String value) {
|
||||
return new ImageUploadFieldBuilder(name, label, value);
|
||||
}
|
||||
|
|
|
@ -82,17 +82,19 @@ public class FormHandle<T extends Entity> {
|
|||
* go to the read-only-view of the specified form to indicate a successful form post
|
||||
* or stay within the edit-mode of the form and indicate errors or field validation messages
|
||||
* to the user on error case.
|
||||
*
|
||||
*
|
||||
* @param postResult The form post result
|
||||
* @param action the action that was applied with the form post
|
||||
* @return the new Action that was used to stay on page or go the read-only-view of the form */
|
||||
public Action handleFormPost(final Result<T> postResult, final Action action) {
|
||||
return postResult
|
||||
.map(result -> {
|
||||
final Action resultAction = action.createNew()
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "true")
|
||||
.withEntityKey(result.getEntityKey());
|
||||
action.pageContext().publishPageEvent(new ActionEvent(resultAction, false));
|
||||
Action resultAction = action.createNew()
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "true");
|
||||
if (resultAction.getEntityKey() == null) {
|
||||
resultAction = resultAction.withEntityKey(result.getEntityKey());
|
||||
}
|
||||
action.pageContext().firePageEvent(new ActionEvent(resultAction, false));
|
||||
return resultAction;
|
||||
})
|
||||
.onErrorDo(this::handleError)
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.eclipse.swt.widgets.Label;
|
|||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
|
||||
|
||||
public final class ImageUploadFieldBuilder extends FieldBuilder {
|
||||
public final class ImageUploadFieldBuilder extends FieldBuilder<String> {
|
||||
|
||||
ImageUploadFieldBuilder(final String name, final String label, final String value) {
|
||||
super(name, label, value);
|
||||
|
|
|
@ -30,7 +30,7 @@ import ch.ethz.seb.sebserver.gui.widget.Selection;
|
|||
import ch.ethz.seb.sebserver.gui.widget.Selection.Type;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public final class SelectionFieldBuilder extends FieldBuilder {
|
||||
public final class SelectionFieldBuilder extends FieldBuilder<String> {
|
||||
|
||||
final Supplier<List<Tuple<String>>> itemsSupplier;
|
||||
Consumer<Form> selectionListener = null;
|
||||
|
|
|
@ -13,9 +13,10 @@ import org.eclipse.swt.layout.GridData;
|
|||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
public final class TextFieldBuilder extends FieldBuilder {
|
||||
public final class TextFieldBuilder extends FieldBuilder<String> {
|
||||
|
||||
boolean isPassword = false;
|
||||
boolean isNumber = false;
|
||||
|
||||
TextFieldBuilder(final String name, final String label, final String value) {
|
||||
super(name, label, value);
|
||||
|
@ -26,6 +27,11 @@ public final class TextFieldBuilder extends FieldBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public TextFieldBuilder asNumber() {
|
||||
this.isNumber = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void build(final FormBuilder builder) {
|
||||
if (this.isPassword && builder.readonly) {
|
||||
|
@ -38,11 +44,11 @@ public final class TextFieldBuilder extends FieldBuilder {
|
|||
builder.valueLabel(builder.formParent, this.value, this.spanInput));
|
||||
builder.setFieldVisible(this.visible, this.name);
|
||||
} else {
|
||||
final Text textInput = new Text(builder.formParent, (this.isPassword)
|
||||
? SWT.LEFT | SWT.BORDER | SWT.PASSWORD
|
||||
: SWT.LEFT | SWT.BORDER);
|
||||
final Text textInput = (this.isNumber)
|
||||
? builder.widgetFactory.numberInput(builder.formParent, null)
|
||||
: builder.widgetFactory.textInput(builder.formParent, this.isPassword);
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||
gridData.heightHint = 15;
|
||||
textInput.setLayoutData(gridData);
|
||||
if (this.value != null) {
|
||||
textInput.setText(this.value);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.form;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ThresholdList;
|
||||
|
||||
public class ThresholdListBuilder extends FieldBuilder<Collection<Threshold>> {
|
||||
|
||||
protected ThresholdListBuilder(
|
||||
final String name,
|
||||
final String label,
|
||||
final Collection<Threshold> value) {
|
||||
|
||||
super(name, label, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void build(final FormBuilder builder) {
|
||||
final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
|
||||
if (builder.readonly || this.readonly) {
|
||||
|
||||
} else {
|
||||
final ThresholdList thresholdList = builder.widgetFactory.thresholdList(
|
||||
builder.formParent,
|
||||
this.value);
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||
thresholdList.setLayoutData(gridData);
|
||||
builder.form.putField(this.name, lab, thresholdList);
|
||||
builder.setFieldVisible(this.visible, this.name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final String thresholdsToFormURLEncodedStringValue(final Collection<Threshold> thresholds) {
|
||||
if (thresholds == null || thresholds.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StringUtils.join(thresholds.stream()
|
||||
.map(t -> String.valueOf(t.getValue()) + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR + t.getColor())
|
||||
.collect(Collectors.toList()),
|
||||
Constants.LIST_SEPARATOR);
|
||||
}
|
||||
|
||||
}
|
|
@ -155,7 +155,7 @@ public interface PageContext {
|
|||
* the specified page event type.
|
||||
*
|
||||
* @param event the concrete PageEvent instance */
|
||||
<T extends PageEvent> void publishPageEvent(T event);
|
||||
<T extends PageEvent> void firePageEvent(T event);
|
||||
|
||||
Action createAction(ActionDefinition actionDefinition);
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public final class Action implements Runnable {
|
|||
try {
|
||||
|
||||
final Action executedAction = this.exec.apply(this);
|
||||
this.pageContext.publishPageEvent(new ActionEvent(executedAction, false));
|
||||
this.pageContext.firePageEvent(new ActionEvent(executedAction, false));
|
||||
|
||||
} catch (final PageMessageException pme) {
|
||||
Action.this.pageContext.publishPageMessage(pme);
|
||||
|
@ -183,7 +183,7 @@ public final class Action implements Runnable {
|
|||
}
|
||||
|
||||
public PageContext publish() {
|
||||
this.pageContext.publishPageEvent(new ActionPublishEvent(this));
|
||||
this.pageContext.firePageEvent(new ActionPublishEvent(this));
|
||||
return this.originalPageContext;
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ public final class Action implements Runnable {
|
|||
if (action.getEntityKey() == null) {
|
||||
final PageContext pageContext = action.pageContext();
|
||||
final Action activityHomeAction = pageContext.createAction(action.definition.activityAlias);
|
||||
action.pageContext.publishPageEvent(new ActionEvent(activityHomeAction, false));
|
||||
action.pageContext.firePageEvent(new ActionEvent(activityHomeAction, false));
|
||||
return activityHomeAction;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ public class PageContextImpl implements PageContext {
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends PageEvent> void publishPageEvent(final T event) {
|
||||
public <T extends PageEvent> void firePageEvent(final T event) {
|
||||
final Class<? extends PageEvent> typeClass = event.getClass();
|
||||
final List<PageEventListener<T>> listeners = new ArrayList<>();
|
||||
ComposerService.traversePageTree(
|
||||
|
|
|
@ -52,6 +52,7 @@ public abstract class RestCall<T> {
|
|||
GET_DEPENDENCIES,
|
||||
NEW,
|
||||
SAVE,
|
||||
DELETE,
|
||||
ACTIVATION_ACTIVATE,
|
||||
ACTIVATION_DEACTIVATE
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class DeleteIndicator extends RestCall<EntityProcessingReport> {
|
||||
|
||||
protected DeleteIndicator() {
|
||||
super(new TypeKey<>(
|
||||
CallType.DELETE,
|
||||
EntityType.INDICATOR,
|
||||
new TypeReference<EntityProcessingReport>() {
|
||||
}),
|
||||
HttpMethod.DELETE,
|
||||
MediaType.APPLICATION_JSON_UTF8,
|
||||
API.EXAM_INDICATOR_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -229,7 +229,7 @@ public class TableFilter<ROW extends Entity> {
|
|||
|
||||
@Override
|
||||
FilterComponent build(final Composite parent) {
|
||||
this.textInput = new Text(parent, SWT.LEFT | SWT.BORDER);
|
||||
this.textInput = TableFilter.this.entityTable.widgetFactory.textInput(parent, false);
|
||||
this.textInput.setLayoutData(this.rowData);
|
||||
return this;
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ public class TableFilter<ROW extends Entity> {
|
|||
.withMonthOfYear(this.selector.getMonth())
|
||||
.withDayOfMonth(this.selector.getDay());
|
||||
|
||||
return date.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
return date.toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public class ColorSelection extends Composite implements Selection {
|
|||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
gridLayout.horizontalSpacing = 0;
|
||||
setLayout(gridLayout);
|
||||
|
||||
this.colorDialog = new ColorDialog(this.getShell(), SWT.NONE);
|
||||
|
|
|
@ -47,7 +47,9 @@ public class MultiSelectionCombo extends Composite implements Selection {
|
|||
private final List<Tuple<Control>> selectionControls = new ArrayList<>();
|
||||
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
||||
private final Map<String, String> mapping = new HashMap<>();
|
||||
//private final List<Tuple<String>> mapping = new ArrayList<>();
|
||||
|
||||
private final GridData comboCell;
|
||||
private final GridData actionCell;
|
||||
|
||||
MultiSelectionCombo(final Composite parent, final WidgetFactory widgetFactory) {
|
||||
super(parent, SWT.NONE);
|
||||
|
@ -57,22 +59,23 @@ public class MultiSelectionCombo extends Composite implements Selection {
|
|||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
gridLayout.horizontalSpacing = 0;
|
||||
setLayout(gridLayout);
|
||||
|
||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||
|
||||
this.combo = new Combo(this, SWT.NONE);
|
||||
final GridData comboCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
this.combo.setLayoutData(comboCell);
|
||||
this.comboCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
this.combo.setLayoutData(this.comboCell);
|
||||
|
||||
final Label imageButton = widgetFactory.imageButton(
|
||||
ImageIcon.ADD_BOX,
|
||||
this,
|
||||
new LocTextKey("Add"),
|
||||
this::addComboSelection);
|
||||
final GridData actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||
actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
||||
imageButton.setLayoutData(actionCell);
|
||||
this.actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||
this.actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
||||
imageButton.setLayoutData(this.actionCell);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,8 +208,7 @@ public class MultiSelectionCombo extends Composite implements Selection {
|
|||
private void adaptColumnWidth(final Event event) {
|
||||
try {
|
||||
final int currentTableWidth = this.getClientArea().width;
|
||||
final GridData comboCell = (GridData) this.combo.getLayoutData();
|
||||
comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
||||
this.comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
||||
this.layout();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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/.
|
||||
|
@ -8,6 +8,202 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.widget;
|
||||
|
||||
public class ThresholdList {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Selection.Type;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
public class ThresholdList extends Composite {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ThresholdList.class);
|
||||
private static final long serialVersionUID = -2305091471607040280L;
|
||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
||||
|
||||
private static final LocTextKey valueTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.value");
|
||||
private static final LocTextKey colorTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.color");
|
||||
private static final LocTextKey addTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.add");
|
||||
private static final LocTextKey removeTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.remove");
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final List<Entry> thresholds = new ArrayList<>();
|
||||
|
||||
private final GridData valueCell;
|
||||
private final GridData colorCell;
|
||||
private final GridData actionCell;
|
||||
|
||||
ThresholdList(final Composite parent, final WidgetFactory widgetFactory) {
|
||||
super(parent, SWT.NONE);
|
||||
this.widgetFactory = widgetFactory;
|
||||
|
||||
final GridLayout gridLayout = new GridLayout(3, false);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
gridLayout.horizontalSpacing = 0;
|
||||
setLayout(gridLayout);
|
||||
|
||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||
|
||||
final Label valueTitle = widgetFactory.labelLocalized(this, CustomVariant.TITLE_LABEL, valueTextKey);
|
||||
this.valueCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
valueTitle.setLayoutData(this.valueCell);
|
||||
|
||||
final Label colorTitle = widgetFactory.labelLocalized(this, CustomVariant.TITLE_LABEL, colorTextKey);
|
||||
this.colorCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
colorTitle.setLayoutData(this.colorCell);
|
||||
|
||||
final Label imageButton = widgetFactory.imageButton(
|
||||
ImageIcon.ADD_BOX,
|
||||
this,
|
||||
addTextKey,
|
||||
this::addThreshold);
|
||||
this.actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||
imageButton.setLayoutData(this.actionCell);
|
||||
}
|
||||
|
||||
public void setThresholds(final Collection<Threshold> thresholds) {
|
||||
clearList();
|
||||
if (thresholds != null) {
|
||||
thresholds
|
||||
.stream()
|
||||
.forEach(this::addThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Threshold> getThresholds() {
|
||||
removeInvalidListEntries();
|
||||
return this.thresholds
|
||||
.stream()
|
||||
.map(entry -> new Threshold(entry.getValue(), entry.getColor()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void removeInvalidListEntries() {
|
||||
this.thresholds
|
||||
.stream()
|
||||
.filter(entry -> entry.getValue() == null || StringUtils.isBlank(entry.getColor()))
|
||||
.collect(Collectors.toList())
|
||||
.stream()
|
||||
.forEach(entry -> removeThreshold(entry));
|
||||
}
|
||||
|
||||
private void clearList() {
|
||||
this.thresholds.stream()
|
||||
.forEach(e -> e.dispose());
|
||||
this.thresholds.clear();
|
||||
}
|
||||
|
||||
private void addThreshold(final Event event) {
|
||||
addThreshold((Threshold) null);
|
||||
}
|
||||
|
||||
private void addThreshold(final Threshold threshold) {
|
||||
final Text valueInput = this.widgetFactory.numberInput(this, s -> Double.parseDouble(s));
|
||||
final GridData valueCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
valueInput.setLayoutData(valueCell);
|
||||
|
||||
final Selection selector = this.widgetFactory.selectionLocalized(Type.COLOR, this, null);
|
||||
final GridData selectorCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
selectorCell.horizontalIndent = 2;
|
||||
selector.adaptToControl().setLayoutData(selectorCell);
|
||||
|
||||
final Label imageButton = this.widgetFactory.imageButton(
|
||||
ImageIcon.REMOVE_BOX,
|
||||
this,
|
||||
removeTextKey,
|
||||
null);
|
||||
final GridData actionCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
imageButton.setLayoutData(actionCell);
|
||||
|
||||
if (threshold != null) {
|
||||
if (threshold.value != null) {
|
||||
valueInput.setText(threshold.value.toString());
|
||||
}
|
||||
if (threshold.color != null) {
|
||||
selector.select(threshold.color);
|
||||
}
|
||||
}
|
||||
|
||||
final Entry entry = new Entry(valueInput, selector, imageButton);
|
||||
this.thresholds.add(entry);
|
||||
|
||||
this.getParent().layout();
|
||||
}
|
||||
|
||||
private void removeThreshold(final Entry entry) {
|
||||
if (this.thresholds.remove(entry)) {
|
||||
entry.dispose();
|
||||
}
|
||||
|
||||
this.getParent().layout();
|
||||
}
|
||||
|
||||
private void adaptColumnWidth(final Event event) {
|
||||
try {
|
||||
// TODO
|
||||
final int currentTableWidth = this.getClientArea().width;
|
||||
final int dynWidth = currentTableWidth - ACTION_COLUMN_WIDTH;
|
||||
final int colWidth = dynWidth / 2;
|
||||
this.valueCell.widthHint = colWidth;
|
||||
this.colorCell.widthHint = colWidth;
|
||||
this.layout();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final class Entry {
|
||||
final Text valueInput;
|
||||
final Selection colorSelector;
|
||||
final Label removeButton;
|
||||
|
||||
Entry(final Text valueInput, final Selection colorSelector, final Label removeButton) {
|
||||
super();
|
||||
this.valueInput = valueInput;
|
||||
this.colorSelector = colorSelector;
|
||||
this.removeButton = removeButton;
|
||||
removeButton.addListener(SWT.MouseDown, event -> removeThreshold(this));
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
this.valueInput.dispose();
|
||||
this.colorSelector.adaptToControl().dispose();
|
||||
this.removeButton.dispose();
|
||||
}
|
||||
|
||||
Double getValue() {
|
||||
if (this.valueInput == null || StringUtils.isBlank(this.valueInput.getText())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Double.parseDouble(this.valueInput.getText());
|
||||
}
|
||||
|
||||
String getColor() {
|
||||
if (this.colorSelector == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.colorSelector.getSelectionValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.widget;
|
|||
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -30,6 +31,7 @@ import org.eclipse.swt.widgets.Listener;
|
|||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -39,6 +41,7 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
|
@ -242,6 +245,35 @@ public class WidgetFactory {
|
|||
return labelLocalized;
|
||||
}
|
||||
|
||||
public Text textInput(final Composite content) {
|
||||
return textInput(content, false);
|
||||
}
|
||||
|
||||
public Text passwordInput(final Composite content) {
|
||||
return textInput(content, true);
|
||||
}
|
||||
|
||||
public Text textInput(final Composite content, final boolean password) {
|
||||
return new Text(content, (password)
|
||||
? SWT.LEFT | SWT.BORDER | SWT.PASSWORD
|
||||
: SWT.LEFT | SWT.BORDER);
|
||||
}
|
||||
|
||||
public Text numberInput(final Composite content, final Consumer<String> numberCheck) {
|
||||
final Text numberInput = new Text(content, SWT.RIGHT | SWT.BORDER);
|
||||
if (numberCheck != null) {
|
||||
numberInput.addListener(SWT.Verify, event -> {
|
||||
final String value = event.text;
|
||||
try {
|
||||
numberCheck.accept(value);
|
||||
} catch (final Exception e) {
|
||||
event.doit = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return numberInput;
|
||||
}
|
||||
|
||||
public Tree treeLocalized(final Composite parent, final int style) {
|
||||
final Tree tree = new Tree(parent, style);
|
||||
this.injectI18n(tree);
|
||||
|
@ -343,6 +375,14 @@ public class WidgetFactory {
|
|||
return selection;
|
||||
}
|
||||
|
||||
public ThresholdList thresholdList(final Composite parent, final Collection<Threshold> values) {
|
||||
final ThresholdList thresholdList = new ThresholdList(parent, this);
|
||||
if (values != null) {
|
||||
thresholdList.setThresholds(values);
|
||||
}
|
||||
return thresholdList;
|
||||
}
|
||||
|
||||
public ImageUpload imageUploadLocalized(
|
||||
final Composite parent,
|
||||
final LocTextKey locTextKey,
|
||||
|
|
|
@ -21,17 +21,26 @@ import org.apache.ibatis.type.JdbcType;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
|
||||
/** Joda DateTime resolver for MyBatis TIMESTAMP to DateTime conversion and vis versa. This is used to convert MyBatis
|
||||
* TIMESTAMP type to Joda-Time's DateTime
|
||||
*
|
||||
* NOTE: The TIMESTAMP is always stored and read in UTC time-zone. */
|
||||
public class JodaTimeTypeResolver extends BaseTypeHandler<DateTime> {
|
||||
|
||||
static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
||||
.forPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZoneUTC();
|
||||
|
||||
/** Date-Time formatter with milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss.S */
|
||||
static final DateTimeFormatter DATE_TIME_PATTERN_UTC_MILLIS = DateTimeFormat
|
||||
.forPattern("yyyy-MM-dd HH:mm:ss.S")
|
||||
.withZoneUTC();
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JodaTimeTypeResolver.class);
|
||||
|
||||
@Override
|
||||
|
@ -68,7 +77,7 @@ public class JodaTimeTypeResolver extends BaseTypeHandler<DateTime> {
|
|||
return getDateTime(supplier.get());
|
||||
} catch (final Exception e) {
|
||||
log.error("while trying to parse LocalDateTime; value: " + dateFormattedString + " format: "
|
||||
+ Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS, e);
|
||||
+ DATE_TIME_PATTERN_UTC_NO_MILLIS, e);
|
||||
throw new RuntimeException("Failed to parse date-time from SQL string: " + dateFormattedString, e);
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +96,7 @@ public class JodaTimeTypeResolver extends BaseTypeHandler<DateTime> {
|
|||
// NOTE: This create a DateTime in UTC time.zone with no time-zone-offset.
|
||||
final LocalDateTime localDateTime = LocalDateTime.parse(
|
||||
dateFormattedString,
|
||||
Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final DateTime dateTime = localDateTime.toDateTime(DateTimeZone.UTC);
|
||||
|
||||
return dateTime;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
@ -21,7 +20,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
|||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.JodaTimeTypeResolver;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
/** A Map containing various filter criteria from a certain API request.
|
||||
* This is used as a data object that can be used to collect API request parameter
|
||||
|
@ -76,27 +75,15 @@ public class FilterMap extends POSTMapper {
|
|||
}
|
||||
|
||||
public DateTime getQuizFromTime() {
|
||||
final String value = getString(QuizData.FILTER_ATTR_START_TIME);
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
return JodaTimeTypeResolver.getDateTime(value);
|
||||
return Utils.toDateTime(getString(QuizData.FILTER_ATTR_START_TIME));
|
||||
}
|
||||
|
||||
public DateTime getExamFromTime() {
|
||||
final String value = getString(Exam.FILTER_ATTR_FROM);
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
return JodaTimeTypeResolver.getDateTime(value);
|
||||
return Utils.toDateTime(getString(Exam.FILTER_ATTR_FROM));
|
||||
}
|
||||
|
||||
public DateTime getSebClientConfigFromTime() {
|
||||
final String value = getString(SebClientConfig.FILTER_ATTR_FROM);
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
return JodaTimeTypeResolver.getDateTime(value);
|
||||
return Utils.toDateTime(getString(SebClientConfig.FILTER_ATTR_FROM));
|
||||
}
|
||||
|
||||
public Long getLmsSetupId() {
|
||||
|
|
|
@ -187,7 +187,7 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
BooleanUtils.toIntegerObject(exam.active));
|
||||
|
||||
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||
return this.examRecordMapper.selectByPrimaryKey(exam.id);
|
||||
return this.examRecordMapper.selectByPrimaryKey(examRecord.getId());
|
||||
}
|
||||
|
||||
final ExamRecord examRecord = new ExamRecord(
|
||||
|
|
|
@ -12,6 +12,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.*;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -23,6 +24,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||
|
@ -217,6 +219,10 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
final Set<EntityKey> examEntities = (bulkAction.sourceType == EntityType.EXAM)
|
||||
? bulkAction.sources
|
||||
: bulkAction.extractKeys(EntityType.EXAM);
|
||||
|
|
|
@ -57,25 +57,25 @@ final class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
this.mockups = new ArrayList<>();
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz1", institutionId, lmsSetupId, lmsType, "Demo Quiz 1", "Demo Quit Mockup",
|
||||
"2020-01-01T09:00:00", "2021-01-01T09:00:00", "http://lms.mockup.com/api/"));
|
||||
"2020-01-01T09:00:00Z", "2021-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz2", institutionId, lmsSetupId, lmsType, "Demo Quiz 2", "Demo Quit Mockup",
|
||||
"2020-01-01T09:00:00", "2021-01-01T09:00:00", "http://lms.mockup.com/api/"));
|
||||
"2020-01-01T09:00:00Z", "2021-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz3", institutionId, lmsSetupId, lmsType, "Demo Quiz 3", "Demo Quit Mockup",
|
||||
"2018-07-30T09:00:00", "2018-08-01T00:00:00", "http://lms.mockup.com/api/"));
|
||||
"2018-07-30T09:00:00Z", "2018-08-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz4", institutionId, lmsSetupId, lmsType, "Demo Quiz 4", "Demo Quit Mockup",
|
||||
"2018-01-01T00:00:00", "2019-01-01T00:00:00", "http://lms.mockup.com/api/"));
|
||||
"2018-01-01T00:00:00Z", "2019-01-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz5", institutionId, lmsSetupId, lmsType, "Demo Quiz 5", "Demo Quit Mockup",
|
||||
"2018-01-01T09:00:00", "2021-01-01T09:00:00", "http://lms.mockup.com/api/"));
|
||||
"2018-01-01T09:00:00Z", "2021-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz6", institutionId, lmsSetupId, lmsType, "Demo Quiz 6", "Demo Quit Mockup",
|
||||
"2018-01-01T09:00:00", "2021-01-01T09:00:00", "http://lms.mockup.com/api/"));
|
||||
"2018-01-01T09:00:00Z", "2021-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz7", institutionId, lmsSetupId, lmsType, "Demo Quiz 7", "Demo Quit Mockup",
|
||||
"2018-01-01T09:00:00", "2021-01-01T09:00:00", "http://lms.mockup.com/api/"));
|
||||
"2018-01-01T09:00:00Z", "2021-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -109,34 +109,6 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private UserInfo checkPasswordChange(final UserInfo info, final PasswordChange passwordChange) {
|
||||
final SEBServerUser currentUser = this.userDAO.sebServerUserByUsername(this.authorization
|
||||
.getUserService()
|
||||
.getCurrentUser().getUsername())
|
||||
.getOrThrow();
|
||||
|
||||
if (!this.userPasswordEncoder.matches(passwordChange.getPassword(), currentUser.getPassword())) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_PASSWORD,
|
||||
"user:oldPassword:password.wrong")));
|
||||
}
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"user:retypedNewPassword:password.mismatch")));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<UserMod> validForCreate(final UserMod userInfo) {
|
||||
return super.validForCreate(userInfo)
|
||||
|
@ -219,4 +191,31 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
});
|
||||
}
|
||||
|
||||
private UserInfo checkPasswordChange(final UserInfo info, final PasswordChange passwordChange) {
|
||||
final SEBServerUser currentUser = this.userDAO.sebServerUserByUsername(this.authorization
|
||||
.getUserService()
|
||||
.getCurrentUser().getUsername())
|
||||
.getOrThrow();
|
||||
|
||||
if (!this.userPasswordEncoder.matches(passwordChange.getPassword(), currentUser.getPassword())) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_PASSWORD,
|
||||
"user:oldPassword:password.wrong")));
|
||||
}
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"user:retypedNewPassword:password.mismatch")));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ sebserver.lmssetup.action.list.view=View LMS Setup
|
|||
sebserver.lmssetup.action.list.modify=Edit LMS Setup
|
||||
sebserver.lmssetup.action.modify=Edit
|
||||
sebserver.lmssetup.action.test=Test Setup
|
||||
sebserver.lmssetup.action.test.ok=Successfully connect to the LMSs course API
|
||||
sebserver.lmssetup.action.test.ok=Successfully connected to the course API
|
||||
sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0}
|
||||
sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0}
|
||||
sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.<br/>Please check the connection parameter for this LMS Setup
|
||||
|
@ -227,15 +227,15 @@ sebserver.exam.list.empty=No Exams has been found. Please adapt the filter or im
|
|||
sebserver.exam.action.list=Exam
|
||||
sebserver.exam.action.list.view=View Exam
|
||||
sebserver.exam.action.list.modify=Edit Exam
|
||||
sebserver.exam.action.modify=Edit
|
||||
sebserver.exam.action.modify=Edit Exam
|
||||
sebserver.exam.action.import=Import From Quizzes
|
||||
sebserver.exam.action.save=Save
|
||||
sebserver.exam.action.activate=Activate
|
||||
sebserver.exam.action.deactivate=Deactivate
|
||||
sebserver.exam.action.save=Save Exam
|
||||
sebserver.exam.action.activate=Activate Exam
|
||||
sebserver.exam.action.deactivate=Deactivate Exam
|
||||
|
||||
sebserver.exam.info.pleaseSelect=Please Select an Exam first
|
||||
|
||||
sebserver.exam.form.title.import=Create From Quiz
|
||||
sebserver.exam.form.title.import=New Exam
|
||||
sebserver.exam.form.title=Exam
|
||||
sebserver.exam.form.lmssetup=LMS Setup
|
||||
sebserver.exam.form.quizid=Quiz Identifier
|
||||
|
@ -266,7 +266,8 @@ sebserver.exam.indicator.type.ERROR_COUNT=Error Count
|
|||
sebserver.exam.indicator.info.pleaseSelect=Please Select an Indicator first
|
||||
|
||||
sebserver.exam.indicator.action.list.new=New Indicator
|
||||
sebserver.exam.indicator.action.list.modify=Modify Indicator
|
||||
sebserver.exam.indicator.action.list.modify=Edit
|
||||
sebserver.exam.indicator.action.list.delete=Delete
|
||||
sebserver.exam.indicator.action.save=Save
|
||||
|
||||
sebserver.exam.indicator.form.title=Indicator
|
||||
|
@ -274,6 +275,11 @@ sebserver.exam.indicator.form.title.new=New Indicator
|
|||
sebserver.exam.indicator.form.exam=Exam
|
||||
sebserver.exam.indicator.form.name=Name
|
||||
sebserver.exam.indicator.form.type=Type
|
||||
sebserver.exam.indicator.form.color=Color
|
||||
sebserver.exam.indicator.form.color=Default Color
|
||||
sebserver.exam.indicator.form.thresholds=Thresholds
|
||||
|
||||
sebserver.exam.indicator.thresholds.list.title=Thresholds
|
||||
sebserver.exam.indicator.thresholds.list.value=Value
|
||||
sebserver.exam.indicator.thresholds.list.color=Color
|
||||
sebserver.exam.indicator.thresholds.list.add=New Threshold
|
||||
sebserver.exam.indicator.thresholds.list.remove=Delete Threshold
|
||||
|
|
|
@ -127,7 +127,7 @@ CREATE TABLE IF NOT EXISTS `indicator` (
|
|||
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||
`type` VARCHAR(45) NOT NULL,
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NULL,
|
||||
INDEX `indicator_exam_idx` (`exam_id` ASC),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `exam_ref`
|
||||
|
@ -357,7 +357,7 @@ CREATE TABLE IF NOT EXISTS `threshold` (
|
|||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
||||
`value` DECIMAL(10,4) NOT NULL,
|
||||
`color` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
||||
CONSTRAINT `indicator_threshold_id`
|
||||
|
|
|
@ -140,7 +140,7 @@ CREATE TABLE IF NOT EXISTS `indicator` (
|
|||
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||
`type` VARCHAR(45) NOT NULL,
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NULL,
|
||||
INDEX `indicator_exam_idx` (`exam_id` ASC),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `exam_ref`
|
||||
|
@ -381,7 +381,7 @@ CREATE TABLE IF NOT EXISTS `threshold` (
|
|||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
||||
`value` DECIMAL(10,4) NOT NULL,
|
||||
`color` VARCHAR(45) NOT NULL,
|
||||
`color` VARCHAR(45) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
||||
CONSTRAINT `indicator_threshold_id`
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.batis;
|
||||
package ch.ethz.seb.sebserver.webservice.datalayer.batis;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
@ -23,9 +23,6 @@ import org.joda.time.DateTimeZone;
|
|||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.JodaTimeTypeResolver;
|
||||
|
||||
public class JodaTimeTypeResolverTest {
|
||||
|
||||
@Test
|
||||
|
@ -53,7 +50,7 @@ public class JodaTimeTypeResolverTest {
|
|||
final int columnIndex = 0;
|
||||
|
||||
final DateTime pointInTime = new DateTime(0, DateTimeZone.UTC);
|
||||
final String pointInTimeString = pointInTime.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String pointInTimeString = pointInTime.toString(JodaTimeTypeResolver.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
assertEquals("1970-01-01 00:00:00", pointInTimeString);
|
||||
|
||||
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
||||
|
@ -64,12 +61,12 @@ public class JodaTimeTypeResolverTest {
|
|||
|
||||
DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
||||
assertNotNull(nullableResult);
|
||||
assertEquals(pointInTimeString, nullableResult.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals(pointInTimeString, nullableResult.toString(JodaTimeTypeResolver.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals(pointInTime, nullableResult);
|
||||
|
||||
nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnIndex);
|
||||
assertNotNull(nullableResult);
|
||||
assertEquals(pointInTimeString, nullableResult.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals(pointInTimeString, nullableResult.toString(JodaTimeTypeResolver.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals(pointInTime, nullableResult);
|
||||
}
|
||||
|
||||
|
@ -78,7 +75,7 @@ public class JodaTimeTypeResolverTest {
|
|||
final String columnName = "timestamp";
|
||||
|
||||
final DateTime pointInTime = new DateTime(0, DateTimeZone.UTC);
|
||||
final String pointInTimeString = pointInTime.toString(Constants.DATE_TIME_PATTERN_UTC_MILLIS);
|
||||
final String pointInTimeString = pointInTime.toString(JodaTimeTypeResolver.DATE_TIME_PATTERN_UTC_MILLIS);
|
||||
assertEquals("1970-01-01 00:00:00.0", pointInTimeString);
|
||||
|
||||
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
||||
|
@ -88,7 +85,8 @@ public class JodaTimeTypeResolverTest {
|
|||
|
||||
final DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
||||
assertNotNull(nullableResult);
|
||||
assertEquals("1970-01-01 00:00:00", nullableResult.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals("1970-01-01 00:00:00",
|
||||
nullableResult.toString(JodaTimeTypeResolver.DATE_TIME_PATTERN_UTC_NO_MILLIS));
|
||||
assertEquals(pointInTime, nullableResult);
|
||||
}
|
||||
|
|
@ -894,7 +894,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
@Test
|
||||
public void deactivateUserAccount() throws Exception {
|
||||
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||
final String examAdminToken = getExamAdmin1();
|
||||
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive")
|
||||
|
@ -957,7 +957,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
@Test
|
||||
public void activateUserAccount() throws Exception {
|
||||
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||
final String examAdminToken = getExamAdmin1();
|
||||
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active")
|
||||
|
|
|
@ -72,12 +72,12 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
@Test
|
||||
public void getAllAsSEBAdminInTimeRange() throws Exception {
|
||||
final DateTime zeroDate = DateTime.parse("1970-01-01 00:00:00", Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final DateTime zeroDate = DateTime.parse("1970-01-01T00:00:00Z", Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
assertEquals("0", String.valueOf(zeroDate.getMillis()));
|
||||
final String sec2 = zeroDate.plus(1000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String sec4 = zeroDate.plus(4000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String sec5 = zeroDate.plus(5000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String sec6 = zeroDate.plus(6000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||
final String sec2 = zeroDate.plus(1000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
final String sec4 = zeroDate.plus(4000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
final String sec5 = zeroDate.plus(5000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
final String sec6 = zeroDate.plus(6000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||
|
||||
final String token = getSebAdminAccess();
|
||||
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||
|
|
Loading…
Add table
Reference in a new issue