diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ExamConfigurationMap.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ExamConfigurationMap.java index 4c2a863a..69040a27 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ExamConfigurationMap.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ExamConfigurationMap.java @@ -10,6 +10,8 @@ package ch.ethz.seb.sebserver.gbl.model.exam; import javax.validation.constraints.NotNull; +import org.joda.time.DateTime; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -20,9 +22,11 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain.CONFIGURATION_NODE; +import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM_CONFIGURATION_MAP; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.GrantEntity; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; @JsonIgnoreProperties(ignoreUnknown = true) @@ -44,6 +48,18 @@ public final class ExamConfigurationMap implements GrantEntity { @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID) public final Long examId; + @JsonProperty(QuizData.QUIZ_ATTR_NAME) + public final String examName; + + @JsonProperty(QuizData.QUIZ_ATTR_DESCRIPTION) + public final String examDescription; + + @JsonProperty(QuizData.QUIZ_ATTR_START_TIME) + public final DateTime examStartTime; + + @JsonProperty(EXAM.ATTR_TYPE) + public final ExamType examType; + @NotNull(message = "examConfigurationMap:configurationNodeId:notNull") @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID) public final Long configurationNodeId; @@ -71,11 +87,14 @@ public final class ExamConfigurationMap implements GrantEntity { @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ID) final Long id, @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_INSTITUTION_ID) final Long institutionId, @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID) final Long examId, + @JsonProperty(QuizData.QUIZ_ATTR_NAME) final String examName, + @JsonProperty(QuizData.QUIZ_ATTR_DESCRIPTION) final String examDescription, + @JsonProperty(QuizData.QUIZ_ATTR_START_TIME) final DateTime examStartTime, + @JsonProperty(EXAM.ATTR_TYPE) final ExamType examType, @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID) final Long configurationNodeId, @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES) final String userNames, @JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret, @JsonProperty(ATTR_CONFIRM_ENCRYPT_SECRET) final CharSequence confirmEncryptSecret, - @JsonProperty(CONFIGURATION_NODE.ATTR_NAME) final String configName, @JsonProperty(CONFIGURATION_NODE.ATTR_DESCRIPTION) final String configDescription, @JsonProperty(CONFIGURATION_NODE.ATTR_STATUS) final ConfigurationStatus configStatus) { @@ -83,6 +102,10 @@ public final class ExamConfigurationMap implements GrantEntity { this.id = id; this.institutionId = institutionId; this.examId = examId; + this.examName = examName; + this.examDescription = examDescription; + this.examStartTime = examStartTime; + this.examType = examType; this.configurationNodeId = configurationNodeId; this.userNames = userNames; this.encryptSecret = encryptSecret; @@ -97,6 +120,12 @@ public final class ExamConfigurationMap implements GrantEntity { this.id = null; this.institutionId = institutionId; this.examId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID); + + this.examName = postParams.getString(QuizData.QUIZ_ATTR_NAME); + this.examDescription = postParams.getString(QuizData.QUIZ_ATTR_DESCRIPTION); + this.examStartTime = postParams.getDateTime(QuizData.QUIZ_ATTR_START_TIME); + this.examType = postParams.getEnum(EXAM.ATTR_TYPE, ExamType.class); + this.configurationNodeId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID); this.userNames = postParams.getString(Domain.EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES); this.encryptSecret = postParams.getCharSequence(Domain.EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET); @@ -137,6 +166,22 @@ public final class ExamConfigurationMap implements GrantEntity { return this.examId; } + public String getExamName() { + return this.examName; + } + + public String getExamDescription() { + return this.examDescription; + } + + public DateTime getExamStartTime() { + return this.examStartTime; + } + + public ExamType getExamType() { + return this.examType; + } + public Long getConfigurationNodeId() { return this.configurationNodeId; } @@ -178,6 +223,10 @@ public final class ExamConfigurationMap implements GrantEntity { this.id, this.institutionId, this.examId, + this.examName, + this.examDescription, + this.examStartTime, + this.examType, this.configurationNodeId, this.userNames, Constants.EMPTY_NOTE, @@ -196,6 +245,14 @@ public final class ExamConfigurationMap implements GrantEntity { builder.append(this.institutionId); builder.append(", examId="); builder.append(this.examId); + builder.append(", examName="); + builder.append(this.examName); + builder.append(", examDescription="); + builder.append(this.examDescription); + builder.append(", examStartTime="); + builder.append(this.examStartTime); + builder.append(", examType="); + builder.append(this.examType); builder.append(", configurationNodeId="); builder.append(this.configurationNodeId); builder.append(", configName="); @@ -206,12 +263,18 @@ public final class ExamConfigurationMap implements GrantEntity { builder.append(this.configStatus); builder.append(", userNames="); builder.append(this.userNames); + builder.append(", encryptSecret="); + builder.append(this.encryptSecret); + builder.append(", confirmEncryptSecret="); + builder.append(this.confirmEncryptSecret); builder.append("]"); return builder.toString(); } public static ExamConfigurationMap createNew(final Exam exam) { - return new ExamConfigurationMap(null, exam.institutionId, exam.id, null, null, null, null, null, null, null); + return new ExamConfigurationMap( + null, exam.institutionId, exam.id, exam.name, exam.description, exam.startTime, exam.type, + null, null, null, null, null, null, null); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java index 3ecfd8d3..7f41b9b8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java @@ -8,6 +8,7 @@ package ch.ethz.seb.sebserver.gui.content; +import java.util.function.BiConsumer; import java.util.function.BooleanSupplier; import java.util.function.Function; @@ -25,8 +26,9 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; -import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus; +import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; +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.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; @@ -43,6 +45,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamConsistency; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamPage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; @@ -58,23 +61,25 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; @GuiProfile public class ExamList implements TemplateComposer { - private static final LocTextKey PAGE_TITLE_KEY = + static final String EXAM_LIST_COLUMN_STARTTIME = + "sebserver.exam.list.column.starttime"; + static final LocTextKey PAGE_TITLE_KEY = new LocTextKey("sebserver.exam.list.title"); - private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = + static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = new LocTextKey("sebserver.exam.list.action.no.modify.privilege"); - private final static LocTextKey EMPTY_SELECTION_TEXT_KEY = + final static LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.exam.info.pleaseSelect"); - private final static LocTextKey COLUMN_TITLE_INSTITUTION_KEY = + final static LocTextKey COLUMN_TITLE_INSTITUTION_KEY = new LocTextKey("sebserver.exam.list.column.institution"); - private final static LocTextKey COLUMN_TITLE_LMS_KEY = + final static LocTextKey COLUMN_TITLE_LMS_KEY = new LocTextKey("sebserver.exam.list.column.lmssetup"); - private final static LocTextKey COLUMN_TITLE_NAME_KEY = + final static LocTextKey COLUMN_TITLE_NAME_KEY = new LocTextKey("sebserver.exam.list.column.name"); - private final static LocTextKey COLUMN_TITLE_TYPE_KEY = + final static LocTextKey COLUMN_TITLE_TYPE_KEY = new LocTextKey("sebserver.exam.list.column.type"); - private final static LocTextKey NO_MODIFY_OF_OUT_DATED_EXAMS = + final static LocTextKey NO_MODIFY_OF_OUT_DATED_EXAMS = new LocTextKey("sebserver.exam.list.modify.out.dated"); - private final static LocTextKey EMPTY_LIST_TEXT_KEY = + final static LocTextKey EMPTY_LIST_TEXT_KEY = new LocTextKey("sebserver.exam.list.empty"); private final TableFilterAttribute institutionFilter; @@ -139,8 +144,8 @@ public class ExamList implements TemplateComposer { this.pageService.entityTableBuilder(restService.getRestCall(GetExamPage.class)) .withEmptyMessage(EMPTY_LIST_TEXT_KEY) .withPaging(this.pageSize) - .withRowDecorator(this::decorateOnExamConsistency) - + .withRowDecorator(decorateOnExamConsistency(this.pageService)) + .withColumnIf( isSebAdmin, () -> new ColumnDefinition( @@ -167,7 +172,7 @@ public class ExamList implements TemplateComposer { .withColumn(new ColumnDefinition<>( QuizData.QUIZ_ATTR_START_TIME, new LocTextKey( - "sebserver.exam.list.column.starttime", + EXAM_LIST_COLUMN_STARTTIME, i18nSupport.getUsersTimeZoneTitleSuffix()), Exam::getStartTime) .withFilter(new TableFilterAttribute( @@ -178,7 +183,7 @@ public class ExamList implements TemplateComposer { .toString())) .sortable()) - .withColumn(new ColumnDefinition<>( + .withColumn(new ColumnDefinition( Domain.EXAM.ATTR_TYPE, COLUMN_TITLE_TYPE_KEY, this.resourceService::localizedExamTypeName) @@ -205,13 +210,13 @@ public class ExamList implements TemplateComposer { .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - action -> this.modifyExam(action, table), + action -> modifyExam(action, table), EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> userGrant.im() && table.hasAnyContent()); } - private PageAction modifyExam(final PageAction action, final EntityTable table) { + static final PageAction modifyExam(final PageAction action, final EntityTable table) { final Exam exam = table.getSelectedROWData(); if (exam == null) { @@ -227,27 +232,41 @@ public class ExamList implements TemplateComposer { return action.withEntityKey(action.getSingleSelection()); } - - private void decorateOnExamConsistency(TableItem item, Exam exam) { + + static final BiConsumer decorateOnExamMapConsistency( + final PageService pageService) { + + return (item, examMap) -> { + pageService.getRestService().getBuilder(GetExam.class) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examMap.examId)) + .call() + .ifPresent(exam -> decorateOnExamConsistency(item, exam, pageService)); + }; + } + + static final BiConsumer decorateOnExamConsistency(final PageService pageService) { + return (item, exam) -> decorateOnExamConsistency(item, exam, pageService); + } + + static final void decorateOnExamConsistency(final TableItem item, final Exam exam, + final PageService pageService) { if (exam.getStatus() != ExamStatus.RUNNING) { return; } - - this.pageService.getRestService().getBuilder(CheckExamConsistency.class) - .withURIVariable(API.PARAM_MODEL_ID, exam.getModelId()) - .call() - .ifPresent(warnings -> { - if (warnings != null && !warnings.isEmpty()) { - item.setData(RWT.CUSTOM_VARIANT, CustomVariant.WARNING.key); - } - }); + + pageService.getRestService().getBuilder(CheckExamConsistency.class) + .withURIVariable(API.PARAM_MODEL_ID, exam.getModelId()) + .call() + .ifPresent(warnings -> { + if (warnings != null && !warnings.isEmpty()) { + item.setData(RWT.CUSTOM_VARIANT, CustomVariant.WARNING.key); + } + }); } private static Function examLmsSetupNameFunction(final ResourceService resourceService) { return exam -> resourceService.getLmsSetupNameFunction() .apply(String.valueOf(exam.lmsSetupId)); } - - } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java index bf37c254..8ce8a256 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java @@ -101,7 +101,7 @@ public class MonitoringRunningExamList implements TemplateComposer { Exam::getName) .withFilter(this.nameFilter) .sortable()) - .withColumn(new ColumnDefinition<>( + .withColumn(new ColumnDefinition( Domain.EXAM.ATTR_TYPE, COLUMN_TITLE_TYPE_KEY, this.resourceService::localizedExamTypeName) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImport.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImport.java index 75fdfbc6..81f266f0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImport.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImport.java @@ -9,6 +9,7 @@ package ch.ethz.seb.sebserver.gui.content; import java.io.InputStream; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -48,7 +49,7 @@ public final class SebExamConfigImport { dialog.open( SebExamConfigPropForm.FORM_IMPORT_TEXT_KEY, - formHandle -> doImport( + (Consumer>) formHandle -> doImport( pageService, formHandle), importFormContext::cancelUpload, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java index 4f1bf1a0..ecd53dfb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java @@ -25,6 +25,7 @@ import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; +import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; @@ -38,6 +39,7 @@ import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageService; +import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; @@ -45,12 +47,15 @@ import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigPlaintextDownload; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportConfigKey; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; +import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; @@ -88,7 +93,6 @@ public class SebExamConfigPropForm implements TemplateComposer { static final LocTextKey FORM_COPY_TEXT_KEY = new LocTextKey("sebserver.examconfig.action.copy"); - static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED = new LocTextKey("sebserver.examconfig.action.state-change.confirm"); @@ -199,7 +203,8 @@ public class SebExamConfigPropForm implements TemplateComposer { final boolean settingsReadonly = examConfig.status == ConfigurationStatus.IN_USE; final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class); final PageContext actionContext = formContext.clearEntityKeys(); - this.pageService.pageActionBuilder(actionContext) + final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(actionContext); + actionBuilder .newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW) .publishIf(() -> writeGrant && isReadonly) @@ -258,6 +263,45 @@ public class SebExamConfigPropForm implements TemplateComposer { .withExec(this.pageService.backToCurrentFunction()) .publishIf(() -> !isReadonly); + if (isAttachedToExam) { + final EntityTable table = + this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class)) + .withRestCallAdapter(restCall -> restCall.withQueryParam( + ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())) + .withPaging(1) + .hideNavigation() + .withRowDecorator(ExamList.decorateOnExamMapConsistency(this.pageService)) + + .withColumn(new ColumnDefinition<>( + QuizData.QUIZ_ATTR_NAME, + ExamList.COLUMN_TITLE_NAME_KEY, + ExamConfigurationMap::getExamName)) + + .withColumn(new ColumnDefinition<>( + QuizData.QUIZ_ATTR_START_TIME, + new LocTextKey( + ExamList.EXAM_LIST_COLUMN_STARTTIME, + this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()), + ExamConfigurationMap::getExamStartTime)) + + .withColumn(new ColumnDefinition( + Domain.EXAM.ATTR_TYPE, + ExamList.COLUMN_TITLE_TYPE_KEY, + resourceService::localizedExamTypeName)) + + .withDefaultAction(actionBuilder + .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) + .create()) + + .compose(pageContext.copyOf(content)); + + actionBuilder + + .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) + .withSelect(table::getSelection, PageAction::applySingleSelection, + ExamList.EMPTY_SELECTION_TEXT_KEY) + .publishIf(table::hasAnyContent); + } } private LocTextKey stateChangeConfirm( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java index e23adb37..ce040086 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java @@ -447,6 +447,15 @@ public class ResourceService { .getText(SEB_CONNECTION_STATUS_KEY_PREFIX + name, name); } + public String localizedExamTypeName(final ExamConfigurationMap examMap) { + if (examMap.examType == null) { + return Constants.EMPTY_NOTE; + } + + return this.i18nSupport + .getText(ResourceService.EXAM_TYPE_PREFIX + examMap.examType.name()); + } + public String localizedExamTypeName(final Exam exam) { if (exam.type == null) { return Constants.EMPTY_NOTE; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CompositeTableFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CompositeTableFieldBuilder.java index e79944df..bf6fe7a2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CompositeTableFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CompositeTableFieldBuilder.java @@ -13,6 +13,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.SWT; @@ -209,15 +210,14 @@ public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder { if (this.tableContext.getViewContext().readonly) { dialog.open( new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row), - rowVals -> { - }, - () -> { - }, builder); } else { dialog.open( new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row), - rowVals -> applyFormValues(this.values, rowVals, selectionIndex), + (Consumer>) rowVals -> applyFormValues( + this.values, + rowVals, + selectionIndex), () -> this.tableContext.getValueChangeListener() .tableChanged(extractTableValue(this.values)), builder); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java index 4bd1a072..db014494 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java @@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -199,7 +200,10 @@ public class TableFieldBuilder extends AbstractTableFieldBuilder { ExamConfigurationService.getTablePopupTitleKey( this.attribute, this.tableContext.getViewContext().i18nSupport), - rowVals -> applyFormValues(this.values, rowVals, selectionIndex), + (Consumer>) rowVals -> applyFormValues( + this.values, + rowVals, + selectionIndex), () -> this.tableContext.getValueChangeListener() .tableChanged(extractTableValue(this.values)), builder); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java index 2691eefa..14d2166b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ModalInputDialog.java @@ -67,6 +67,17 @@ public class ModalInputDialog extends Dialog { return this; } + public void open( + final LocTextKey title, + final ModalInputDialogComposer contentComposer) { + + open( + title, + (Predicate) t -> true, + () -> { + }, contentComposer); + } + public void open( final LocTextKey title, final Consumer callback, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index cb434640..bb21362b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -55,7 +55,6 @@ import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; 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.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; public class EntityTable { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java index 23e3aaea..66f6b931 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamConfigurationMapDAOImpl.java @@ -30,6 +30,8 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; 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.ExamType; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @@ -49,6 +51,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler; @@ -62,17 +65,20 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { private final ExamConfigurationMapRecordMapper examConfigurationMapRecordMapper; private final ConfigurationNodeRecordMapper configurationNodeRecordMapper; private final ClientCredentialService clientCredentialService; + private final ExamDAO examDAO; protected ExamConfigurationMapDAOImpl( final ExamRecordMapper examRecordMapper, final ExamConfigurationMapRecordMapper examConfigurationMapRecordMapper, final ConfigurationNodeRecordMapper configurationNodeRecordMapper, - final ClientCredentialService clientCredentialService) { + final ClientCredentialService clientCredentialService, + final ExamDAO examDAO) { this.examRecordMapper = examRecordMapper; this.examConfigurationMapRecordMapper = examConfigurationMapRecordMapper; this.configurationNodeRecordMapper = configurationNodeRecordMapper; this.clientCredentialService = clientCredentialService; + this.examDAO = examDAO; } @Override @@ -340,20 +346,27 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO { private Result toDomainModel(final ExamConfigurationMapRecord record) { return Result.tryCatch(() -> { - final ConfigurationNodeRecord selectByPrimaryKey = this.configurationNodeRecordMapper + final ConfigurationNodeRecord config = this.configurationNodeRecordMapper .selectByPrimaryKey(record.getConfigurationNodeId()); - final String status = selectByPrimaryKey.getStatus(); + final String status = config.getStatus(); + + final Exam exam = this.examDAO.byPK(record.getExamId()) + .getOr(null); return new ExamConfigurationMap( record.getId(), record.getInstitutionId(), record.getExamId(), + (exam != null) ? exam.name : null, + (exam != null) ? exam.description : null, + (exam != null) ? exam.startTime : null, + (exam != null) ? exam.type : ExamType.UNDEFINED, record.getConfigurationNodeId(), record.getUserNames(), null, null, - selectByPrimaryKey.getName(), - selectByPrimaryKey.getDescription(), + config.getName(), + config.getDescription(), (StringUtils.isNotBlank(status)) ? ConfigurationStatus.valueOf(status) : null); }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java index 33b4feec..600d511a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java @@ -320,7 +320,9 @@ public abstract class EntityController { BulkActionType.HARD_DELETE, entityType, new EntityName(modelId, entityType, entity.getName())))) + .flatMap(this::logBulkAction) + .flatMap(this::notifyDeleted) .getOrThrow(); } @@ -370,6 +372,10 @@ public abstract class EntityController { return Result.of(entity); } + protected Result notifyDeleted(final EntityProcessingReport deletionReport) { + return Result.of(deletionReport); + } + protected Result checkReadAccess(final T entity) { final GrantEntity grantEntity = toGrantEntity(entity); if (grantEntity != null) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamConfigurationMappingController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamConfigurationMappingController.java index 4013e81b..78a83c1a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamConfigurationMappingController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamConfigurationMappingController.java @@ -20,6 +20,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; @@ -119,7 +120,7 @@ public class ExamConfigurationMappingController extends EntityController entity); } + @Override + protected Result notifyDeleted(final EntityProcessingReport deletionReport) { + // update the attached configurations state to "Ready" + deletionReport.source + .stream() + .forEach(entityKey -> { + this.configurationNodeDAO.save(new ConfigurationNode( + Long.parseLong(entityKey.modelId), + null, + null, + null, + null, + null, + null, + ConfigurationStatus.READY_TO_USE)); + }); + + return super.notifyDeleted(deletionReport); + } + private ExamConfigurationMap checkPasswordMatch(final ExamConfigurationMap entity) { if (entity.hasEncryptionSecret() && !entity.encryptSecret.equals(entity.confirmEncryptSecret)) { throw new APIMessageException(APIMessage.fieldValidationError(