SEBSERV-73 added exam reference table to exam config view page

This commit is contained in:
anhefti 2019-10-24 13:44:55 +02:00
parent fb13c62eeb
commit bac8aba3eb
13 changed files with 238 additions and 48 deletions

View file

@ -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);
}
}

View file

@ -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<Exam>(
@ -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<Exam>(
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<Exam> table) {
static final PageAction modifyExam(final PageAction action, final EntityTable<Exam> 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<TableItem, ExamConfigurationMap> 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<TableItem, Exam> 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<Exam, String> examLmsSetupNameFunction(final ResourceService resourceService) {
return exam -> resourceService.getLmsSetupNameFunction()
.apply(String.valueOf(exam.lmsSetupId));
}
}

View file

@ -101,7 +101,7 @@ public class MonitoringRunningExamList implements TemplateComposer {
Exam::getName)
.withFilter(this.nameFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<Exam>(
Domain.EXAM.ATTR_TYPE,
COLUMN_TITLE_TYPE_KEY,
this.resourceService::localizedExamTypeName)

View file

@ -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<ConfigurationNode>>) formHandle -> doImport(
pageService,
formHandle),
importFormContext::cancelUpload,

View file

@ -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<ExamConfigurationMap> 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<ExamConfigurationMap>(
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(

View file

@ -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;

View file

@ -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<Map<Long, TableValue>>) rowVals -> applyFormValues(
this.values,
rowVals,
selectionIndex),
() -> this.tableContext.getValueChangeListener()
.tableChanged(extractTableValue(this.values)),
builder);

View file

@ -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<Map<Long, TableValue>>) rowVals -> applyFormValues(
this.values,
rowVals,
selectionIndex),
() -> this.tableContext.getValueChangeListener()
.tableChanged(extractTableValue(this.values)),
builder);

View file

@ -67,6 +67,17 @@ public class ModalInputDialog<T> extends Dialog {
return this;
}
public void open(
final LocTextKey title,
final ModalInputDialogComposer<T> contentComposer) {
open(
title,
(Predicate<T>) t -> true,
() -> {
}, contentComposer);
}
public void open(
final LocTextKey title,
final Consumer<T> callback,

View file

@ -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<ROW extends Entity> {

View file

@ -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<ExamConfigurationMap> 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);
});
}

View file

@ -320,7 +320,9 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
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<T extends Entity, M extends Entity> {
return Result.of(entity);
}
protected Result<EntityProcessingReport> notifyDeleted(final EntityProcessingReport deletionReport) {
return Result.of(deletionReport);
}
protected Result<T> checkReadAccess(final T entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {

View file

@ -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<ExamCon
// update the attached configurations state to "In Use"
return this.configurationNodeDAO.save(new ConfigurationNode(
entity.configurationNodeId,
entity.institutionId,
null,
null,
null,
null,
@ -129,6 +130,26 @@ public class ExamConfigurationMappingController extends EntityController<ExamCon
.map(config -> entity);
}
@Override
protected Result<EntityProcessingReport> 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(