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)
|
.forPattern(DEFAULT_DATE_TIME_FORMAT)
|
||||||
.withZoneUTC();
|
.withZoneUTC();
|
||||||
|
|
||||||
/** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */
|
// /** 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
|
// // TODO check if this works with DEFAULT_DATE_TIME_FORMAT
|
||||||
@Deprecated
|
// @Deprecated
|
||||||
public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
// public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
||||||
.forPattern("yyyy-MM-dd HH:mm:ss")
|
// .forPattern("yyyy-MM-dd HH:mm:ss")
|
||||||
.withZoneUTC();
|
// .withZoneUTC();
|
||||||
|
//
|
||||||
/** Date-Time formatter with milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss.S */
|
// /** Date-Time formatter with milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss.S */
|
||||||
@Deprecated
|
// @Deprecated
|
||||||
public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_MILLIS = DateTimeFormat
|
// public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_MILLIS = DateTimeFormat
|
||||||
.forPattern("yyyy-MM-dd HH:mm:ss.S")
|
// .forPattern("yyyy-MM-dd HH:mm:ss.S")
|
||||||
.withZoneUTC();
|
// .withZoneUTC();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ public final class Utils {
|
||||||
|
|
||||||
public static Result<Long> dateTimeStringToTimestamp(final String startTime) {
|
public static Result<Long> dateTimeStringToTimestamp(final String startTime) {
|
||||||
return Result.tryCatch(() -> {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dateString.contains(".")) {
|
return DateTime.parse(dateString, Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||||
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_MILLIS);
|
|
||||||
} else {
|
|
||||||
return DateTime.parse(dateString, Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Long toMilliSeconds(final String dateString) {
|
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.action.Action;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
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.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.GetExam;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam;
|
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
|
// new PageContext with actual EntityKey
|
||||||
final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey());
|
final PageContext formContext = pageContext.withEntityKey(exam.getEntityKey());
|
||||||
|
|
||||||
// the default page layout with title
|
// the default page layout with title
|
||||||
final LocTextKey titleKey = new LocTextKey(
|
final LocTextKey titleKey = new LocTextKey(
|
||||||
importFromQuizData
|
importFromQuizData
|
||||||
|
@ -270,11 +272,13 @@ public class ExamForm implements TemplateComposer {
|
||||||
.publishIf(() -> modifyGrant)
|
.publishIf(() -> modifyGrant)
|
||||||
|
|
||||||
.createAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
|
.createAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
|
||||||
|
.withParentEntityKey(entityKey)
|
||||||
.withSelect(indicatorTable::getSelection, Action::applySingleSelection, emptySelectionTextKey)
|
.withSelect(indicatorTable::getSelection, Action::applySingleSelection, emptySelectionTextKey)
|
||||||
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent())
|
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent())
|
||||||
|
|
||||||
.createAction(ActionDefinition.EXAM_INDICATOR_DELETE_FROM_LIST)
|
.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());
|
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent());
|
||||||
|
|
||||||
// TODO List of attached SEB Configurations
|
// 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) {
|
private Result<Exam> getExistingExam(final EntityKey entityKey, final RestService restService) {
|
||||||
return restService.getBuilder(GetExam.class)
|
return restService.getBuilder(GetExam.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||||
|
@ -330,7 +343,7 @@ public class ExamForm implements TemplateComposer {
|
||||||
if (importFromQuizData) {
|
if (importFromQuizData) {
|
||||||
final PageContext pageContext = action.pageContext();
|
final PageContext pageContext = action.pageContext();
|
||||||
final Action activityHomeAction = pageContext.createAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST);
|
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;
|
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.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
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.exam.Indicator;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||||
import ch.ethz.seb.sebserver.gui.form.PageFormService;
|
import ch.ethz.seb.sebserver.gui.form.PageFormService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
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.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
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.GetIndicator;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewIndicator;
|
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.api.exam.SaveIndicator;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -46,9 +43,6 @@ public class IndicatorForm implements TemplateComposer {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(IndicatorForm.class);
|
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 PageFormService pageFormService;
|
||||||
private final ResourceService resourceService;
|
private final ResourceService resourceService;
|
||||||
|
|
||||||
|
@ -62,12 +56,8 @@ public class IndicatorForm implements TemplateComposer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compose(final PageContext pageContext) {
|
public void compose(final PageContext pageContext) {
|
||||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
|
||||||
final RestService restService = this.resourceService.getRestService();
|
final RestService restService = this.resourceService.getRestService();
|
||||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||||
final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
|
|
||||||
|
|
||||||
final UserInfo user = currentUser.get();
|
|
||||||
final EntityKey entityKey = pageContext.getEntityKey();
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||||
final boolean isNew = entityKey == null;
|
final boolean isNew = entityKey == null;
|
||||||
|
@ -134,9 +124,13 @@ public class IndicatorForm implements TemplateComposer {
|
||||||
(indicator.type != null) ? indicator.type.name() : null,
|
(indicator.type != null) ? indicator.type.name() : null,
|
||||||
this.resourceService::indicatorTypeResources))
|
this.resourceService::indicatorTypeResources))
|
||||||
.addField(FormBuilder.colorSelection(
|
.addField(FormBuilder.colorSelection(
|
||||||
Domain.INDICATOR.ATTR_TYPE,
|
Domain.INDICATOR.ATTR_COLOR,
|
||||||
"sebserver.exam.indicator.form.color",
|
"sebserver.exam.indicator.form.color",
|
||||||
indicator.defaultColor))
|
indicator.defaultColor))
|
||||||
|
.addField(FormBuilder.thresholdList(
|
||||||
|
Domain.THRESHOLD.REFERENCE_NAME,
|
||||||
|
"sebserver.exam.indicator.form.thresholds",
|
||||||
|
indicator.getThresholds()))
|
||||||
.buildFor((isNew)
|
.buildFor((isNew)
|
||||||
? restService.getRestCall(NewIndicator.class)
|
? restService.getRestCall(NewIndicator.class)
|
||||||
: restService.getRestCall(SaveIndicator.class));
|
: restService.getRestCall(SaveIndicator.class));
|
||||||
|
@ -144,7 +138,7 @@ public class IndicatorForm implements TemplateComposer {
|
||||||
// propagate content actions to action-pane
|
// propagate content actions to action-pane
|
||||||
formContext.clearEntityKeys()
|
formContext.clearEntityKeys()
|
||||||
.createAction(ActionDefinition.EXAM_INDICATOR_SAVE)
|
.createAction(ActionDefinition.EXAM_INDICATOR_SAVE)
|
||||||
.withParentEntityKey(parentEntityKey)
|
.withEntityKey(parentEntityKey)
|
||||||
.withExec(formHandle::processFormSave)
|
.withExec(formHandle::processFormSave)
|
||||||
.publishIf(() -> !isReadonly)
|
.publishIf(() -> !isReadonly)
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,7 @@ public class InstitutionForm implements TemplateComposer {
|
||||||
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
||||||
|
|
||||||
.createAction(ActionDefinition.INSTITUTION_SAVE)
|
.createAction(ActionDefinition.INSTITUTION_SAVE)
|
||||||
|
.withEntityKey(entityKey)
|
||||||
.withExec(formHandle::processFormSave)
|
.withExec(formHandle::processFormSave)
|
||||||
.publishIf(() -> !isReadonly)
|
.publishIf(() -> !isReadonly)
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,7 @@ public class LmsSetupForm implements TemplateComposer {
|
||||||
.publishIf(() -> writeGrant && readonly && institutionActive && !lmsSetup.isActive())
|
.publishIf(() -> writeGrant && readonly && institutionActive && !lmsSetup.isActive())
|
||||||
|
|
||||||
.createAction(ActionDefinition.LMS_SETUP_SAVE)
|
.createAction(ActionDefinition.LMS_SETUP_SAVE)
|
||||||
|
.withEntityKey(entityKey)
|
||||||
.withExec(formHandle::processFormSave)
|
.withExec(formHandle::processFormSave)
|
||||||
.publishIf(() -> !readonly)
|
.publishIf(() -> !readonly)
|
||||||
|
|
||||||
|
|
|
@ -66,13 +66,13 @@ public class LoginPage implements TemplateComposer {
|
||||||
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
||||||
name.setLayoutData(new GridData(300, -1));
|
name.setLayoutData(new GridData(300, -1));
|
||||||
name.setAlignment(SWT.BOTTOM);
|
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));
|
loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||||
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
|
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||||
gridData.verticalIndent = 10;
|
gridData.verticalIndent = 10;
|
||||||
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
|
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
|
||||||
pwd.setLayoutData(gridData);
|
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));
|
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||||
|
|
||||||
final Button button = this.widgetFactory.buttonLocalized(loginGroup, "sebserver.login.login");
|
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())
|
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
|
||||||
|
|
||||||
.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||||
|
.withEntityKey(entityKey)
|
||||||
.withExec(action -> {
|
.withExec(action -> {
|
||||||
final Action postChanges = formHandle.processFormSave(action);
|
final Action postChanges = formHandle.processFormSave(action);
|
||||||
if (ownAccount) {
|
if (ownAccount) {
|
||||||
|
|
|
@ -175,7 +175,15 @@ public class ActionPane implements TemplateComposer {
|
||||||
new ArrayList<>(this.actionTrees.entrySet())
|
new ArrayList<>(this.actionTrees.entrySet())
|
||||||
.stream()
|
.stream()
|
||||||
.forEach(entry -> {
|
.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());
|
this.actionTrees.remove(entry.getKey());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -162,7 +162,7 @@ public class ActivitiesPane implements TemplateComposer {
|
||||||
if (mainPageState.action == null) {
|
if (mainPageState.action == null) {
|
||||||
mainPageState.action = getActivitySelection(navigation.getItem(0));
|
mainPageState.action = getActivitySelection(navigation.getItem(0));
|
||||||
}
|
}
|
||||||
pageContext.publishPageEvent(
|
pageContext.firePageEvent(
|
||||||
new ActionEvent(mainPageState.action, false));
|
new ActionEvent(mainPageState.action, false));
|
||||||
navigation.select(navigation.getItem(0));
|
navigation.select(navigation.getItem(0));
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ public class ActivitiesPane implements TemplateComposer {
|
||||||
final Action action = getActivitySelection(treeItem);
|
final Action action = getActivitySelection(treeItem);
|
||||||
if (mainPageState.action.definition != action.definition) {
|
if (mainPageState.action.definition != action.definition) {
|
||||||
mainPageState.action = action;
|
mainPageState.action = action;
|
||||||
composerCtx.publishPageEvent(
|
composerCtx.firePageEvent(
|
||||||
new ActionEvent(action, true));
|
new ActionEvent(action, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ package ch.ethz.seb.sebserver.gui.form;
|
||||||
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
public abstract class FieldBuilder {
|
public abstract class FieldBuilder<T> {
|
||||||
int spanLabel = -1;
|
int spanLabel = -1;
|
||||||
int spanInput = -1;
|
int spanInput = -1;
|
||||||
int spanEmptyCell = -1;
|
int spanEmptyCell = -1;
|
||||||
|
@ -22,55 +22,55 @@ public abstract class FieldBuilder {
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final String label;
|
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.name = name;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withLabelSpan(final int span) {
|
public FieldBuilder<T> withLabelSpan(final int span) {
|
||||||
this.spanLabel = span;
|
this.spanLabel = span;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withInputSpan(final int span) {
|
public FieldBuilder<T> withInputSpan(final int span) {
|
||||||
this.spanInput = span;
|
this.spanInput = span;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withEmptyCellSpan(final int span) {
|
public FieldBuilder<T> withEmptyCellSpan(final int span) {
|
||||||
this.spanEmptyCell = span;
|
this.spanEmptyCell = span;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withEmptyCellSeparation(final boolean separation) {
|
public FieldBuilder<T> withEmptyCellSeparation(final boolean separation) {
|
||||||
this.autoEmptyCellSeparation = separation;
|
this.autoEmptyCellSeparation = separation;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withGroup(final String group) {
|
public FieldBuilder<T> withGroup(final String group) {
|
||||||
this.group = group;
|
this.group = group;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder withCondition(final BooleanSupplier condition) {
|
public FieldBuilder<T> withCondition(final BooleanSupplier condition) {
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder readonly(final boolean readonly) {
|
public FieldBuilder<T> readonly(final boolean readonly) {
|
||||||
this.readonly = readonly;
|
this.readonly = readonly;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder visibleIf(final boolean visible) {
|
public FieldBuilder<T> visibleIf(final boolean visible) {
|
||||||
this.visible = visible;
|
this.visible = visible;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldBuilder readonlyIf(final BooleanSupplier readonly) {
|
public FieldBuilder<T> readonlyIf(final BooleanSupplier readonly) {
|
||||||
this.readonly = readonly != null && readonly.getAsBoolean();
|
this.readonly = readonly != null && readonly.getAsBoolean();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.form;
|
package ch.ethz.seb.sebserver.gui.form;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
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.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
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.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
|
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.ImageUpload;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
||||||
|
import ch.ethz.seb.sebserver.gui.widget.ThresholdList;
|
||||||
|
|
||||||
public final class Form implements FormBinding {
|
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()) {
|
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
|
||||||
entry.getValue()
|
entry.getValue()
|
||||||
.stream()
|
.stream()
|
||||||
.forEach(ffa -> appendFormUrlEncodedValue(buffer, entry.getKey(), ffa.getValue()));
|
.forEach(ffa -> appendFormUrlEncodedValue(buffer, entry.getKey(), ffa.getStringValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
|
@ -106,6 +109,10 @@ public final class Form implements FormBinding {
|
||||||
this.formFields.add(name, createAccessor(label, field));
|
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(
|
public void putField(
|
||||||
final String name,
|
final String name,
|
||||||
final Label label,
|
final Label label,
|
||||||
|
@ -174,7 +181,7 @@ public final class Form implements FormBinding {
|
||||||
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
|
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
|
||||||
entry.getValue()
|
entry.getValue()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(ffa -> StringUtils.isNoneBlank(ffa.getValue()))
|
.filter(ffa -> StringUtils.isNoneBlank(ffa.getStringValue()))
|
||||||
.forEach(ffa -> ffa.putJsonValue(entry.getKey(), this.objectRoot));
|
.forEach(ffa -> ffa.putJsonValue(entry.getKey(), this.objectRoot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,14 +190,12 @@ public final class Form implements FormBinding {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
private FormFieldAccessor createAccessor(final Label label, final Label field) {
|
private FormFieldAccessor createAccessor(final Label label, final Label field) {
|
||||||
return new FormFieldAccessor(label, field) {
|
return new FormFieldAccessor(label, field) {
|
||||||
@Override public String getValue() { return null; }
|
@Override public String getStringValue() { return null; }
|
||||||
@Override public void setValue(final String value) { field.setText(value); }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private FormFieldAccessor createAccessor(final Label label, final Text text) {
|
private FormFieldAccessor createAccessor(final Label label, final Text text) {
|
||||||
return new FormFieldAccessor(label, text) {
|
return new FormFieldAccessor(label, text) {
|
||||||
@Override public String getValue() { return text.getText(); }
|
@Override public String getStringValue() { return text.getText(); }
|
||||||
@Override public void setValue(final String value) { text.setText(value); }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private FormFieldAccessor createAccessor(final Label label, final Selection selection) {
|
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) {
|
final BiConsumer<Tuple<String>, ObjectNode> jsonValueAdapter) {
|
||||||
|
|
||||||
return new FormFieldAccessor(label, selection.adaptToControl(), jsonValueAdapter) {
|
return new FormFieldAccessor(label, selection.adaptToControl(), jsonValueAdapter) {
|
||||||
@Override public String getValue() { return selection.getSelectionValue(); }
|
@Override public String getStringValue() { return selection.getSelectionValue(); }
|
||||||
@Override public void setValue(final String value) { selection.select(value); }
|
};
|
||||||
|
}
|
||||||
|
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) {
|
private FormFieldAccessor createAccessor(final Label label, final ImageUpload imageUpload) {
|
||||||
return new FormFieldAccessor(label, imageUpload) {
|
return new FormFieldAccessor(label, imageUpload) {
|
||||||
@Override public String getValue() { return imageUpload.getImageBase64(); }
|
@Override public String getStringValue() { return imageUpload.getImageBase64(); }
|
||||||
@Override public void setValue(final String value) { imageUpload.setImageBase64(value); }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//@formatter:on
|
//@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
|
* 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
|
* 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);
|
final String[] split = StringUtils.split(value, Constants.LIST_SEPARATOR_CHAR);
|
||||||
if (split != null) {
|
for (int i = 0; i < split.length; i++) {
|
||||||
for (int i = 0; i < split.length; i++) {
|
if (StringUtils.isBlank(split[i])) {
|
||||||
if (StringUtils.isNoneBlank(split[i])) {
|
continue;
|
||||||
if (buffer.length() > 0) {
|
}
|
||||||
buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
|
|
||||||
}
|
if (buffer.length() > 0) {
|
||||||
buffer.append(name)
|
buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
}
|
||||||
.append(split[i]);
|
|
||||||
}
|
// 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) {
|
final ObjectNode jsonNode) {
|
||||||
if (StringUtils.isNoneBlank(tuple._2)) {
|
if (StringUtils.isNoneBlank(tuple._2)) {
|
||||||
final ArrayNode arrayNode = jsonNode.putArray(tuple._1);
|
final ArrayNode arrayNode = jsonNode.putArray(tuple._1);
|
||||||
|
@ -280,17 +316,15 @@ public final class Form implements FormBinding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String getValue();
|
public abstract String getStringValue();
|
||||||
|
|
||||||
public abstract void setValue(String value);
|
|
||||||
|
|
||||||
public void setVisible(final boolean visible) {
|
public void setVisible(final boolean visible) {
|
||||||
this.label.setVisible(visible);
|
this.label.setVisible(visible);
|
||||||
this.control.setVisible(visible);
|
this.control.setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void putJsonValue(final String key, final ObjectNode objectRoot) {
|
public void putJsonValue(final String key, final ObjectNode objectRoot) {
|
||||||
this.jsonValueAdapter.accept(new Tuple<>(key, getValue()), objectRoot);
|
this.jsonValueAdapter.accept(new Tuple<>(key, getStringValue()), objectRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setError(final String errorTooltip) {
|
public void setError(final String errorTooltip) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.form;
|
package ch.ethz.seb.sebserver.gui.form;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Supplier;
|
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.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
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.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
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);
|
private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
|
||||||
|
|
||||||
final WidgetFactory widgetFactory;
|
final WidgetFactory widgetFactory;
|
||||||
|
final JSONMapper jsonMapper;
|
||||||
private final PolyglotPageService polyglotPageService;
|
private final PolyglotPageService polyglotPageService;
|
||||||
public final PageContext pageContext;
|
public final PageContext pageContext;
|
||||||
public final Composite formParent;
|
public final Composite formParent;
|
||||||
|
@ -58,6 +61,7 @@ public class FormBuilder {
|
||||||
final int rows) {
|
final int rows) {
|
||||||
|
|
||||||
this.widgetFactory = widgetFactory;
|
this.widgetFactory = widgetFactory;
|
||||||
|
this.jsonMapper = jsonMapper;
|
||||||
this.polyglotPageService = polyglotPageService;
|
this.polyglotPageService = polyglotPageService;
|
||||||
this.pageContext = pageContext;
|
this.pageContext = pageContext;
|
||||||
this.form = new Form(jsonMapper);
|
this.form = new Form(jsonMapper);
|
||||||
|
@ -145,7 +149,7 @@ public class FormBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FormBuilder addField(final FieldBuilder template) {
|
public FormBuilder addField(final FieldBuilder<?> template) {
|
||||||
if (template.condition == null || template.condition.getAsBoolean()) {
|
if (template.condition == null || template.condition.getAsBoolean()) {
|
||||||
template.spanLabel = (template.spanLabel < 0) ? this.defaultSpanLabel : template.spanLabel;
|
template.spanLabel = (template.spanLabel < 0) ? this.defaultSpanLabel : template.spanLabel;
|
||||||
template.spanInput = (template.spanInput < 0) ? this.defaultSpanInput : template.spanInput;
|
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);
|
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) {
|
public static ImageUploadFieldBuilder imageUpload(final String name, final String label, final String value) {
|
||||||
return new ImageUploadFieldBuilder(name, label, 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
|
* 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
|
* or stay within the edit-mode of the form and indicate errors or field validation messages
|
||||||
* to the user on error case.
|
* to the user on error case.
|
||||||
*
|
*
|
||||||
* @param postResult The form post result
|
* @param postResult The form post result
|
||||||
* @param action the action that was applied with the form post
|
* @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 */
|
* @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) {
|
public Action handleFormPost(final Result<T> postResult, final Action action) {
|
||||||
return postResult
|
return postResult
|
||||||
.map(result -> {
|
.map(result -> {
|
||||||
final Action resultAction = action.createNew()
|
Action resultAction = action.createNew()
|
||||||
.withAttribute(AttributeKeys.READ_ONLY, "true")
|
.withAttribute(AttributeKeys.READ_ONLY, "true");
|
||||||
.withEntityKey(result.getEntityKey());
|
if (resultAction.getEntityKey() == null) {
|
||||||
action.pageContext().publishPageEvent(new ActionEvent(resultAction, false));
|
resultAction = resultAction.withEntityKey(result.getEntityKey());
|
||||||
|
}
|
||||||
|
action.pageContext().firePageEvent(new ActionEvent(resultAction, false));
|
||||||
return resultAction;
|
return resultAction;
|
||||||
})
|
})
|
||||||
.onErrorDo(this::handleError)
|
.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.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
|
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) {
|
ImageUploadFieldBuilder(final String name, final String label, final String value) {
|
||||||
super(name, label, 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.Selection.Type;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
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;
|
final Supplier<List<Tuple<String>>> itemsSupplier;
|
||||||
Consumer<Form> selectionListener = null;
|
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.Label;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
public final class TextFieldBuilder extends FieldBuilder {
|
public final class TextFieldBuilder extends FieldBuilder<String> {
|
||||||
|
|
||||||
boolean isPassword = false;
|
boolean isPassword = false;
|
||||||
|
boolean isNumber = false;
|
||||||
|
|
||||||
TextFieldBuilder(final String name, final String label, final String value) {
|
TextFieldBuilder(final String name, final String label, final String value) {
|
||||||
super(name, label, value);
|
super(name, label, value);
|
||||||
|
@ -26,6 +27,11 @@ public final class TextFieldBuilder extends FieldBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TextFieldBuilder asNumber() {
|
||||||
|
this.isNumber = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void build(final FormBuilder builder) {
|
void build(final FormBuilder builder) {
|
||||||
if (this.isPassword && builder.readonly) {
|
if (this.isPassword && builder.readonly) {
|
||||||
|
@ -38,11 +44,11 @@ public final class TextFieldBuilder extends FieldBuilder {
|
||||||
builder.valueLabel(builder.formParent, this.value, this.spanInput));
|
builder.valueLabel(builder.formParent, this.value, this.spanInput));
|
||||||
builder.setFieldVisible(this.visible, this.name);
|
builder.setFieldVisible(this.visible, this.name);
|
||||||
} else {
|
} else {
|
||||||
final Text textInput = new Text(builder.formParent, (this.isPassword)
|
final Text textInput = (this.isNumber)
|
||||||
? SWT.LEFT | SWT.BORDER | SWT.PASSWORD
|
? builder.widgetFactory.numberInput(builder.formParent, null)
|
||||||
: SWT.LEFT | SWT.BORDER);
|
: builder.widgetFactory.textInput(builder.formParent, this.isPassword);
|
||||||
|
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||||
gridData.heightHint = 15;
|
|
||||||
textInput.setLayoutData(gridData);
|
textInput.setLayoutData(gridData);
|
||||||
if (this.value != null) {
|
if (this.value != null) {
|
||||||
textInput.setText(this.value);
|
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.
|
* the specified page event type.
|
||||||
*
|
*
|
||||||
* @param event the concrete PageEvent instance */
|
* @param event the concrete PageEvent instance */
|
||||||
<T extends PageEvent> void publishPageEvent(T event);
|
<T extends PageEvent> void firePageEvent(T event);
|
||||||
|
|
||||||
Action createAction(ActionDefinition actionDefinition);
|
Action createAction(ActionDefinition actionDefinition);
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ public final class Action implements Runnable {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final Action executedAction = this.exec.apply(this);
|
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) {
|
} catch (final PageMessageException pme) {
|
||||||
Action.this.pageContext.publishPageMessage(pme);
|
Action.this.pageContext.publishPageMessage(pme);
|
||||||
|
@ -183,7 +183,7 @@ public final class Action implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageContext publish() {
|
public PageContext publish() {
|
||||||
this.pageContext.publishPageEvent(new ActionPublishEvent(this));
|
this.pageContext.firePageEvent(new ActionPublishEvent(this));
|
||||||
return this.originalPageContext;
|
return this.originalPageContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ public final class Action implements Runnable {
|
||||||
if (action.getEntityKey() == null) {
|
if (action.getEntityKey() == null) {
|
||||||
final PageContext pageContext = action.pageContext();
|
final PageContext pageContext = action.pageContext();
|
||||||
final Action activityHomeAction = pageContext.createAction(action.definition.activityAlias);
|
final Action activityHomeAction = pageContext.createAction(action.definition.activityAlias);
|
||||||
action.pageContext.publishPageEvent(new ActionEvent(activityHomeAction, false));
|
action.pageContext.firePageEvent(new ActionEvent(activityHomeAction, false));
|
||||||
return activityHomeAction;
|
return activityHomeAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ public class PageContextImpl implements PageContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@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 Class<? extends PageEvent> typeClass = event.getClass();
|
||||||
final List<PageEventListener<T>> listeners = new ArrayList<>();
|
final List<PageEventListener<T>> listeners = new ArrayList<>();
|
||||||
ComposerService.traversePageTree(
|
ComposerService.traversePageTree(
|
||||||
|
|
|
@ -52,6 +52,7 @@ public abstract class RestCall<T> {
|
||||||
GET_DEPENDENCIES,
|
GET_DEPENDENCIES,
|
||||||
NEW,
|
NEW,
|
||||||
SAVE,
|
SAVE,
|
||||||
|
DELETE,
|
||||||
ACTIVATION_ACTIVATE,
|
ACTIVATION_ACTIVATE,
|
||||||
ACTIVATION_DEACTIVATE
|
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
|
@Override
|
||||||
FilterComponent build(final Composite parent) {
|
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);
|
this.textInput.setLayoutData(this.rowData);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
.withMonthOfYear(this.selector.getMonth())
|
.withMonthOfYear(this.selector.getMonth())
|
||||||
.withDayOfMonth(this.selector.getDay());
|
.withDayOfMonth(this.selector.getDay());
|
||||||
|
|
||||||
return date.toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
return date.toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class ColorSelection extends Composite implements Selection {
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
|
gridLayout.horizontalSpacing = 0;
|
||||||
setLayout(gridLayout);
|
setLayout(gridLayout);
|
||||||
|
|
||||||
this.colorDialog = new ColorDialog(this.getShell(), SWT.NONE);
|
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<Control>> selectionControls = new ArrayList<>();
|
||||||
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
||||||
private final Map<String, String> mapping = new HashMap<>();
|
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) {
|
MultiSelectionCombo(final Composite parent, final WidgetFactory widgetFactory) {
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
|
@ -57,22 +59,23 @@ public class MultiSelectionCombo extends Composite implements Selection {
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
|
gridLayout.horizontalSpacing = 0;
|
||||||
setLayout(gridLayout);
|
setLayout(gridLayout);
|
||||||
|
|
||||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||||
|
|
||||||
this.combo = new Combo(this, SWT.NONE);
|
this.combo = new Combo(this, SWT.NONE);
|
||||||
final GridData comboCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
this.comboCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||||
this.combo.setLayoutData(comboCell);
|
this.combo.setLayoutData(this.comboCell);
|
||||||
|
|
||||||
final Label imageButton = widgetFactory.imageButton(
|
final Label imageButton = widgetFactory.imageButton(
|
||||||
ImageIcon.ADD_BOX,
|
ImageIcon.ADD_BOX,
|
||||||
this,
|
this,
|
||||||
new LocTextKey("Add"),
|
new LocTextKey("Add"),
|
||||||
this::addComboSelection);
|
this::addComboSelection);
|
||||||
final GridData actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
this.actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||||
actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
this.actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
||||||
imageButton.setLayoutData(actionCell);
|
imageButton.setLayoutData(this.actionCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,8 +208,7 @@ public class MultiSelectionCombo extends Composite implements Selection {
|
||||||
private void adaptColumnWidth(final Event event) {
|
private void adaptColumnWidth(final Event event) {
|
||||||
try {
|
try {
|
||||||
final int currentTableWidth = this.getClientArea().width;
|
final int currentTableWidth = this.getClientArea().width;
|
||||||
final GridData comboCell = (GridData) this.combo.getLayoutData();
|
this.comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
||||||
comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
|
||||||
this.layout();
|
this.layout();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to adaptColumnWidth: ", e);
|
log.warn("Failed to adaptColumnWidth: ", e);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* 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
|
* 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/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
@ -8,6 +8,202 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
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 static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.*;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Consumer;
|
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.Table;
|
||||||
import org.eclipse.swt.widgets.TableColumn;
|
import org.eclipse.swt.widgets.TableColumn;
|
||||||
import org.eclipse.swt.widgets.TableItem;
|
import org.eclipse.swt.widgets.TableItem;
|
||||||
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.eclipse.swt.widgets.Tree;
|
import org.eclipse.swt.widgets.Tree;
|
||||||
import org.eclipse.swt.widgets.TreeItem;
|
import org.eclipse.swt.widgets.TreeItem;
|
||||||
import org.slf4j.Logger;
|
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.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
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.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||||
|
@ -242,6 +245,35 @@ public class WidgetFactory {
|
||||||
return labelLocalized;
|
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) {
|
public Tree treeLocalized(final Composite parent, final int style) {
|
||||||
final Tree tree = new Tree(parent, style);
|
final Tree tree = new Tree(parent, style);
|
||||||
this.injectI18n(tree);
|
this.injectI18n(tree);
|
||||||
|
@ -343,6 +375,14 @@ public class WidgetFactory {
|
||||||
return selection;
|
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(
|
public ImageUpload imageUploadLocalized(
|
||||||
final Composite parent,
|
final Composite parent,
|
||||||
final LocTextKey locTextKey,
|
final LocTextKey locTextKey,
|
||||||
|
|
|
@ -21,17 +21,26 @@ import org.apache.ibatis.type.JdbcType;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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
|
/** 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
|
* TIMESTAMP type to Joda-Time's DateTime
|
||||||
*
|
*
|
||||||
* NOTE: The TIMESTAMP is always stored and read in UTC time-zone. */
|
* NOTE: The TIMESTAMP is always stored and read in UTC time-zone. */
|
||||||
public class JodaTimeTypeResolver extends BaseTypeHandler<DateTime> {
|
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);
|
private static final Logger log = LoggerFactory.getLogger(JodaTimeTypeResolver.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,7 +77,7 @@ public class JodaTimeTypeResolver extends BaseTypeHandler<DateTime> {
|
||||||
return getDateTime(supplier.get());
|
return getDateTime(supplier.get());
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("while trying to parse LocalDateTime; value: " + dateFormattedString + " format: "
|
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);
|
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.
|
// NOTE: This create a DateTime in UTC time.zone with no time-zone-offset.
|
||||||
final LocalDateTime localDateTime = LocalDateTime.parse(
|
final LocalDateTime localDateTime = LocalDateTime.parse(
|
||||||
dateFormattedString,
|
dateFormattedString,
|
||||||
Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
||||||
final DateTime dateTime = localDateTime.toDateTime(DateTimeZone.UTC);
|
final DateTime dateTime = localDateTime.toDateTime(DateTimeZone.UTC);
|
||||||
|
|
||||||
return dateTime;
|
return dateTime;
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
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.LmsSetup;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.institution.SebClientConfig;
|
import ch.ethz.seb.sebserver.gbl.model.institution.SebClientConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
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.
|
/** 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
|
* 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() {
|
public DateTime getQuizFromTime() {
|
||||||
final String value = getString(QuizData.FILTER_ATTR_START_TIME);
|
return Utils.toDateTime(getString(QuizData.FILTER_ATTR_START_TIME));
|
||||||
if (StringUtils.isBlank(value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return JodaTimeTypeResolver.getDateTime(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime getExamFromTime() {
|
public DateTime getExamFromTime() {
|
||||||
final String value = getString(Exam.FILTER_ATTR_FROM);
|
return Utils.toDateTime(getString(Exam.FILTER_ATTR_FROM));
|
||||||
if (StringUtils.isBlank(value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return JodaTimeTypeResolver.getDateTime(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime getSebClientConfigFromTime() {
|
public DateTime getSebClientConfigFromTime() {
|
||||||
final String value = getString(SebClientConfig.FILTER_ATTR_FROM);
|
return Utils.toDateTime(getString(SebClientConfig.FILTER_ATTR_FROM));
|
||||||
if (StringUtils.isBlank(value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return JodaTimeTypeResolver.getDateTime(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLmsSetupId() {
|
public Long getLmsSetupId() {
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
BooleanUtils.toIntegerObject(exam.active));
|
BooleanUtils.toIntegerObject(exam.active));
|
||||||
|
|
||||||
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
|
this.examRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||||
return this.examRecordMapper.selectByPrimaryKey(exam.id);
|
return this.examRecordMapper.selectByPrimaryKey(examRecord.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExamRecord examRecord = new ExamRecord(
|
final ExamRecord examRecord = new ExamRecord(
|
||||||
|
|
|
@ -12,6 +12,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -23,6 +24,7 @@ import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
|
@ -217,6 +219,10 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
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)
|
final Set<EntityKey> examEntities = (bulkAction.sourceType == EntityType.EXAM)
|
||||||
? bulkAction.sources
|
? bulkAction.sources
|
||||||
: bulkAction.extractKeys(EntityType.EXAM);
|
: bulkAction.extractKeys(EntityType.EXAM);
|
||||||
|
|
|
@ -57,25 +57,25 @@ final class MockupLmsAPITemplate implements LmsAPITemplate {
|
||||||
this.mockups = new ArrayList<>();
|
this.mockups = new ArrayList<>();
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz1", institutionId, lmsSetupId, lmsType, "Demo Quiz 1", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz2", institutionId, lmsSetupId, lmsType, "Demo Quiz 2", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz3", institutionId, lmsSetupId, lmsType, "Demo Quiz 3", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz4", institutionId, lmsSetupId, lmsType, "Demo Quiz 4", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz5", institutionId, lmsSetupId, lmsType, "Demo Quiz 5", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz6", institutionId, lmsSetupId, lmsType, "Demo Quiz 6", "Demo Quit Mockup",
|
"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(
|
this.mockups.add(new QuizData(
|
||||||
"quiz7", institutionId, lmsSetupId, lmsType, "Demo Quiz 7", "Demo Quit Mockup",
|
"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
|
@Override
|
||||||
|
|
|
@ -109,34 +109,6 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
.collect(Collectors.toList()));
|
.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
|
@Override
|
||||||
protected Result<UserMod> validForCreate(final UserMod userInfo) {
|
protected Result<UserMod> validForCreate(final UserMod userInfo) {
|
||||||
return super.validForCreate(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.list.modify=Edit LMS Setup
|
||||||
sebserver.lmssetup.action.modify=Edit
|
sebserver.lmssetup.action.modify=Edit
|
||||||
sebserver.lmssetup.action.test=Test Setup
|
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.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.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
|
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=Exam
|
||||||
sebserver.exam.action.list.view=View Exam
|
sebserver.exam.action.list.view=View Exam
|
||||||
sebserver.exam.action.list.modify=Edit 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.import=Import From Quizzes
|
||||||
sebserver.exam.action.save=Save
|
sebserver.exam.action.save=Save Exam
|
||||||
sebserver.exam.action.activate=Activate
|
sebserver.exam.action.activate=Activate Exam
|
||||||
sebserver.exam.action.deactivate=Deactivate
|
sebserver.exam.action.deactivate=Deactivate Exam
|
||||||
|
|
||||||
sebserver.exam.info.pleaseSelect=Please Select an Exam first
|
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.title=Exam
|
||||||
sebserver.exam.form.lmssetup=LMS Setup
|
sebserver.exam.form.lmssetup=LMS Setup
|
||||||
sebserver.exam.form.quizid=Quiz Identifier
|
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.info.pleaseSelect=Please Select an Indicator first
|
||||||
|
|
||||||
sebserver.exam.indicator.action.list.new=New Indicator
|
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.action.save=Save
|
||||||
|
|
||||||
sebserver.exam.indicator.form.title=Indicator
|
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.exam=Exam
|
||||||
sebserver.exam.indicator.form.name=Name
|
sebserver.exam.indicator.form.name=Name
|
||||||
sebserver.exam.indicator.form.type=Type
|
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.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,
|
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`type` VARCHAR(45) NOT NULL,
|
`type` VARCHAR(45) NOT NULL,
|
||||||
`name` 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),
|
INDEX `indicator_exam_idx` (`exam_id` ASC),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `exam_ref`
|
CONSTRAINT `exam_ref`
|
||||||
|
@ -357,7 +357,7 @@ CREATE TABLE IF NOT EXISTS `threshold` (
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`value` DECIMAL(10,4) NOT NULL,
|
`value` DECIMAL(10,4) NOT NULL,
|
||||||
`color` VARCHAR(45) NOT NULL,
|
`color` VARCHAR(45) NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
||||||
CONSTRAINT `indicator_threshold_id`
|
CONSTRAINT `indicator_threshold_id`
|
||||||
|
|
|
@ -140,7 +140,7 @@ CREATE TABLE IF NOT EXISTS `indicator` (
|
||||||
`exam_id` BIGINT UNSIGNED NOT NULL,
|
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`type` VARCHAR(45) NOT NULL,
|
`type` VARCHAR(45) NOT NULL,
|
||||||
`name` 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),
|
INDEX `indicator_exam_idx` (`exam_id` ASC),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `exam_ref`
|
CONSTRAINT `exam_ref`
|
||||||
|
@ -381,7 +381,7 @@ CREATE TABLE IF NOT EXISTS `threshold` (
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`value` DECIMAL(10,4) NOT NULL,
|
`value` DECIMAL(10,4) NOT NULL,
|
||||||
`color` VARCHAR(45) NOT NULL,
|
`color` VARCHAR(45) NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
||||||
CONSTRAINT `indicator_threshold_id`
|
CONSTRAINT `indicator_threshold_id`
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* 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.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -23,9 +23,6 @@ import org.joda.time.DateTimeZone;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.JodaTimeTypeResolver;
|
|
||||||
|
|
||||||
public class JodaTimeTypeResolverTest {
|
public class JodaTimeTypeResolverTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -53,7 +50,7 @@ public class JodaTimeTypeResolverTest {
|
||||||
final int columnIndex = 0;
|
final int columnIndex = 0;
|
||||||
|
|
||||||
final DateTime pointInTime = new DateTime(0, DateTimeZone.UTC);
|
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);
|
assertEquals("1970-01-01 00:00:00", pointInTimeString);
|
||||||
|
|
||||||
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
||||||
|
@ -64,12 +61,12 @@ public class JodaTimeTypeResolverTest {
|
||||||
|
|
||||||
DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
||||||
assertNotNull(nullableResult);
|
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);
|
assertEquals(pointInTime, nullableResult);
|
||||||
|
|
||||||
nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnIndex);
|
nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnIndex);
|
||||||
assertNotNull(nullableResult);
|
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);
|
assertEquals(pointInTime, nullableResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +75,7 @@ public class JodaTimeTypeResolverTest {
|
||||||
final String columnName = "timestamp";
|
final String columnName = "timestamp";
|
||||||
|
|
||||||
final DateTime pointInTime = new DateTime(0, DateTimeZone.UTC);
|
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);
|
assertEquals("1970-01-01 00:00:00.0", pointInTimeString);
|
||||||
|
|
||||||
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
final JodaTimeTypeResolver jodaTimeTypeResolver = new JodaTimeTypeResolver();
|
||||||
|
@ -88,7 +85,8 @@ public class JodaTimeTypeResolverTest {
|
||||||
|
|
||||||
final DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
final DateTime nullableResult = jodaTimeTypeResolver.getNullableResult(resultSetMock, columnName);
|
||||||
assertNotNull(nullableResult);
|
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);
|
assertEquals(pointInTime, nullableResult);
|
||||||
}
|
}
|
||||||
|
|
|
@ -894,7 +894,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deactivateUserAccount() throws Exception {
|
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
|
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||||
final String examAdminToken = getExamAdmin1();
|
final String examAdminToken = getExamAdmin1();
|
||||||
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive")
|
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive")
|
||||||
|
@ -957,7 +957,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void activateUserAccount() throws Exception {
|
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
|
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||||
final String examAdminToken = getExamAdmin1();
|
final String examAdminToken = getExamAdmin1();
|
||||||
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active")
|
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active")
|
||||||
|
|
|
@ -72,12 +72,12 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllAsSEBAdminInTimeRange() throws Exception {
|
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()));
|
assertEquals("0", String.valueOf(zeroDate.getMillis()));
|
||||||
final String sec2 = zeroDate.plus(1000).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.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
final String sec4 = zeroDate.plus(4000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||||
final String sec5 = zeroDate.plus(5000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
final String sec5 = zeroDate.plus(5000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||||
final String sec6 = zeroDate.plus(6000).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS);
|
final String sec6 = zeroDate.plus(6000).toString(Constants.STANDARD_DATE_TIME_FORMATTER);
|
||||||
|
|
||||||
final String token = getSebAdminAccess();
|
final String token = getSebAdminAccess();
|
||||||
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||||
|
|
Loading…
Add table
Reference in a new issue