diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java index 1430ae4c..9a678d19 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java @@ -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(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java index 13fa7245..b95c2944 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -113,7 +113,7 @@ public final class Utils { public static Result 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) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java index db1e9f43..25f86c01 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java @@ -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 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; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java index 60b341c3..b2b21349 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/IndicatorForm.java @@ -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) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java index cb3423ee..b1a10eb9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionForm.java @@ -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) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java index 96c66b45..7a6fb26c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java @@ -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) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java index f3976888..06aacd38 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java @@ -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"); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java index 3f92517c..cf3e4609 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java @@ -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) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java index 6c9ed2a4..4b6c6b37 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java @@ -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()); } }); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java index 000352b2..4a530499 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java @@ -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)); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FieldBuilder.java index 51bfb9db..6c66e400 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FieldBuilder.java @@ -10,7 +10,7 @@ package ch.ethz.seb.sebserver.gui.form; import java.util.function.BooleanSupplier; -public abstract class FieldBuilder { +public abstract class FieldBuilder { 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 withLabelSpan(final int span) { this.spanLabel = span; return this; } - public FieldBuilder withInputSpan(final int span) { + public FieldBuilder withInputSpan(final int span) { this.spanInput = span; return this; } - public FieldBuilder withEmptyCellSpan(final int span) { + public FieldBuilder withEmptyCellSpan(final int span) { this.spanEmptyCell = span; return this; } - public FieldBuilder withEmptyCellSeparation(final boolean separation) { + public FieldBuilder withEmptyCellSeparation(final boolean separation) { this.autoEmptyCellSeparation = separation; return this; } - public FieldBuilder withGroup(final String group) { + public FieldBuilder withGroup(final String group) { this.group = group; return this; } - public FieldBuilder withCondition(final BooleanSupplier condition) { + public FieldBuilder withCondition(final BooleanSupplier condition) { this.condition = condition; return this; } - public FieldBuilder readonly(final boolean readonly) { + public FieldBuilder readonly(final boolean readonly) { this.readonly = readonly; return this; } - public FieldBuilder visibleIf(final boolean visible) { + public FieldBuilder visibleIf(final boolean visible) { this.visible = visible; return this; } - public FieldBuilder readonlyIf(final BooleanSupplier readonly) { + public FieldBuilder readonlyIf(final BooleanSupplier readonly) { this.readonly = readonly != null && readonly.getAsBoolean(); return this; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/Form.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/Form.java index f6b9f469..cef06823 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/Form.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/Form.java @@ -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> 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> 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, 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 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 tuple, + private static final void adaptCommaSeparatedStringToJsonArray( + final Tuple 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) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java index 34bc940a..fbbab6f5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormBuilder.java @@ -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 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); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java index 7786183b..e599f15f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java @@ -82,17 +82,19 @@ public class FormHandle { * 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 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) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/ImageUploadFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/ImageUploadFieldBuilder.java index 22c8dd2a..0e484da7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/ImageUploadFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/ImageUploadFieldBuilder.java @@ -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 { ImageUploadFieldBuilder(final String name, final String label, final String value) { super(name, label, value); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java index 41898fcb..074b2ef6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java @@ -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 { final Supplier>> itemsSupplier; Consumer
selectionListener = null; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/TextFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/TextFieldBuilder.java index 75fc526a..c34581fd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/TextFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/TextFieldBuilder.java @@ -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 { 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); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java new file mode 100644 index 00000000..55e507c7 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java @@ -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> { + + protected ThresholdListBuilder( + final String name, + final String label, + final Collection 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 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); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java index 8c76ae95..0b8440b2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java @@ -155,7 +155,7 @@ public interface PageContext { * the specified page event type. * * @param event the concrete PageEvent instance */ - void publishPageEvent(T event); + void firePageEvent(T event); Action createAction(ActionDefinition actionDefinition); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java index 0ebdd0d9..64db755e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java @@ -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; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java index 2ca841f8..1b8d59d9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java @@ -219,7 +219,7 @@ public class PageContextImpl implements PageContext { @Override @SuppressWarnings("unchecked") - public void publishPageEvent(final T event) { + public void firePageEvent(final T event) { final Class typeClass = event.getClass(); final List> listeners = new ArrayList<>(); ComposerService.traversePageTree( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java index 2724dbe2..69f0651e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java @@ -52,6 +52,7 @@ public abstract class RestCall { GET_DEPENDENCIES, NEW, SAVE, + DELETE, ACTIVATION_ACTIVATE, ACTIVATION_DEACTIVATE } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/DeleteIndicator.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/DeleteIndicator.java new file mode 100644 index 00000000..1f03beaa --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/exam/DeleteIndicator.java @@ -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 { + + protected DeleteIndicator() { + super(new TypeKey<>( + CallType.DELETE, + EntityType.INDICATOR, + new TypeReference() { + }), + HttpMethod.DELETE, + MediaType.APPLICATION_JSON_UTF8, + API.EXAM_INDICATOR_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java index 88de55ea..06692b06 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java @@ -229,7 +229,7 @@ public class TableFilter { @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 { .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; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/ColorSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/ColorSelection.java index 25625469..d20be4f8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/ColorSelection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/ColorSelection.java @@ -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); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelectionCombo.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelectionCombo.java index 6ca8de53..de397e73 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelectionCombo.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelectionCombo.java @@ -47,7 +47,9 @@ public class MultiSelectionCombo extends Composite implements Selection { private final List> selectionControls = new ArrayList<>(); private final List> selectedValues = new ArrayList<>(); private final Map mapping = new HashMap<>(); - //private final List> 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); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/ThresholdList.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/ThresholdList.java index d8b73e9b..cb64044a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/ThresholdList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/ThresholdList.java @@ -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 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 thresholds) { + clearList(); + if (thresholds != null) { + thresholds + .stream() + .forEach(this::addThreshold); + } + } + + public Collection 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(); + } + } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index d160a0de..d8d1b12f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -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 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 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, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolver.java b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolver.java index 201a1a43..c582372c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolver.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolver.java @@ -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 { + 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 { 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 { // 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; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java index c93d639a..a62689b3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/FilterMap.java @@ -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() { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index dba5ee6e..9715bdb0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -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( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java index c3d68512..c0d35f09 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/IndicatorDAOImpl.java @@ -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 getDependencies(final BulkAction bulkAction) { + if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) { + return Collections.emptySet(); + } + final Set examEntities = (bulkAction.sourceType == EntityType.EXAM) ? bulkAction.sources : bulkAction.extractKeys(EntityType.EXAM); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java index f22dfa8b..e55968bb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java @@ -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 diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 5fe80609..04365cf9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -109,34 +109,6 @@ public class UserAccountController extends ActivatableEntityController validForCreate(final UserMod userInfo) { return super.validForCreate(userInfo) @@ -219,4 +191,31 @@ public class UserAccountController extends ActivatableEntityControllerPlease 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 diff --git a/src/main/resources/schema-demo.sql b/src/main/resources/schema-demo.sql index 9459a3d7..9c83344d 100644 --- a/src/main/resources/schema-demo.sql +++ b/src/main/resources/schema-demo.sql @@ -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` diff --git a/src/main/resources/schema-dev.sql b/src/main/resources/schema-dev.sql index 6fbd7789..0ab3cf91 100644 --- a/src/main/resources/schema-dev.sql +++ b/src/main/resources/schema-dev.sql @@ -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` diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/batis/JodaTimeTypeResolverTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolverTest.java similarity index 83% rename from src/test/java/ch/ethz/seb/sebserver/webservice/batis/JodaTimeTypeResolverTest.java rename to src/test/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolverTest.java index b92778a9..a1c50686 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/batis/JodaTimeTypeResolverTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/JodaTimeTypeResolverTest.java @@ -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); } diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java index b52a3b53..5dedac96 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java @@ -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") diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java index 8bb9cc62..7c9e94b8 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserActivityLogAPITest.java @@ -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 logs = this.jsonMapper.readValue(