SEBSERV-160 fixed "In Use" for selection
This commit is contained in:
parent
8b9eebfe5b
commit
6396afa53b
7 changed files with 65 additions and 9 deletions
|
@ -26,12 +26,15 @@ 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.Domain.EXAM_CONFIGURATION_MAP;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public final class ExamConfigurationMap implements GrantEntity {
|
public final class ExamConfigurationMap implements GrantEntity {
|
||||||
|
|
||||||
|
private static final String ARR_EXAM_STATUS = "examStatus";
|
||||||
|
|
||||||
public static final String ATTR_CONFIRM_ENCRYPT_SECRET = "confirm_encrypt_secret";
|
public static final String ATTR_CONFIRM_ENCRYPT_SECRET = "confirm_encrypt_secret";
|
||||||
|
|
||||||
public static final String FILTER_ATTR_EXAM_ID = "examId";
|
public static final String FILTER_ATTR_EXAM_ID = "examId";
|
||||||
|
@ -60,6 +63,9 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
@JsonProperty(EXAM.ATTR_TYPE)
|
@JsonProperty(EXAM.ATTR_TYPE)
|
||||||
public final ExamType examType;
|
public final ExamType examType;
|
||||||
|
|
||||||
|
@JsonProperty(ARR_EXAM_STATUS)
|
||||||
|
public final ExamStatus examStatus;
|
||||||
|
|
||||||
@NotNull(message = "examConfigurationMap:configurationNodeId:notNull")
|
@NotNull(message = "examConfigurationMap:configurationNodeId:notNull")
|
||||||
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID)
|
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID)
|
||||||
public final Long configurationNodeId;
|
public final Long configurationNodeId;
|
||||||
|
@ -91,6 +97,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
@JsonProperty(QuizData.QUIZ_ATTR_DESCRIPTION) final String examDescription,
|
@JsonProperty(QuizData.QUIZ_ATTR_DESCRIPTION) final String examDescription,
|
||||||
@JsonProperty(QuizData.QUIZ_ATTR_START_TIME) final DateTime examStartTime,
|
@JsonProperty(QuizData.QUIZ_ATTR_START_TIME) final DateTime examStartTime,
|
||||||
@JsonProperty(EXAM.ATTR_TYPE) final ExamType examType,
|
@JsonProperty(EXAM.ATTR_TYPE) final ExamType examType,
|
||||||
|
@JsonProperty(ARR_EXAM_STATUS) final ExamStatus examStatus,
|
||||||
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID) final Long configurationNodeId,
|
@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_USER_NAMES) final String userNames,
|
||||||
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
|
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
|
||||||
|
@ -106,6 +113,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
this.examDescription = examDescription;
|
this.examDescription = examDescription;
|
||||||
this.examStartTime = examStartTime;
|
this.examStartTime = examStartTime;
|
||||||
this.examType = examType;
|
this.examType = examType;
|
||||||
|
this.examStatus = examStatus;
|
||||||
this.configurationNodeId = configurationNodeId;
|
this.configurationNodeId = configurationNodeId;
|
||||||
this.userNames = userNames;
|
this.userNames = userNames;
|
||||||
this.encryptSecret = encryptSecret;
|
this.encryptSecret = encryptSecret;
|
||||||
|
@ -125,6 +133,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
this.examDescription = postParams.getString(QuizData.QUIZ_ATTR_DESCRIPTION);
|
this.examDescription = postParams.getString(QuizData.QUIZ_ATTR_DESCRIPTION);
|
||||||
this.examStartTime = postParams.getDateTime(QuizData.QUIZ_ATTR_START_TIME);
|
this.examStartTime = postParams.getDateTime(QuizData.QUIZ_ATTR_START_TIME);
|
||||||
this.examType = postParams.getEnum(EXAM.ATTR_TYPE, ExamType.class);
|
this.examType = postParams.getEnum(EXAM.ATTR_TYPE, ExamType.class);
|
||||||
|
this.examStatus = postParams.getEnum(ARR_EXAM_STATUS, ExamStatus.class);
|
||||||
|
|
||||||
this.configurationNodeId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
|
this.configurationNodeId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
|
||||||
this.userNames = postParams.getString(Domain.EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES);
|
this.userNames = postParams.getString(Domain.EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES);
|
||||||
|
@ -149,6 +158,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
this.examDescription = null;
|
this.examDescription = null;
|
||||||
this.examStartTime = null;
|
this.examStartTime = null;
|
||||||
this.examType = null;
|
this.examType = null;
|
||||||
|
this.examStatus = null;
|
||||||
this.configurationNodeId = configurationNodeId;
|
this.configurationNodeId = configurationNodeId;
|
||||||
this.userNames = userNames;
|
this.userNames = userNames;
|
||||||
this.encryptSecret = null;
|
this.encryptSecret = null;
|
||||||
|
@ -205,6 +215,10 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
return this.examType;
|
return this.examType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ExamStatus getExamStatus() {
|
||||||
|
return this.examStatus;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getConfigurationNodeId() {
|
public Long getConfigurationNodeId() {
|
||||||
return this.configurationNodeId;
|
return this.configurationNodeId;
|
||||||
}
|
}
|
||||||
|
@ -250,6 +264,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
this.examDescription,
|
this.examDescription,
|
||||||
this.examStartTime,
|
this.examStartTime,
|
||||||
this.examType,
|
this.examType,
|
||||||
|
this.examStatus,
|
||||||
this.configurationNodeId,
|
this.configurationNodeId,
|
||||||
this.userNames,
|
this.userNames,
|
||||||
Constants.EMPTY_NOTE,
|
Constants.EMPTY_NOTE,
|
||||||
|
@ -296,7 +311,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
||||||
|
|
||||||
public static ExamConfigurationMap createNew(final Exam exam) {
|
public static ExamConfigurationMap createNew(final Exam exam) {
|
||||||
return new ExamConfigurationMap(
|
return new ExamConfigurationMap(
|
||||||
null, exam.institutionId, exam.id, exam.name, exam.description, exam.startTime, exam.type,
|
null, exam.institutionId, exam.id, exam.name, exam.description, exam.startTime, exam.type, exam.status,
|
||||||
null, null, null, null, null, null, null);
|
null, null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class SEBExamConfigBatchStateChangePopup extends AbstractBatchActionWizar
|
||||||
FORM_STATUS_TEXT_KEY,
|
FORM_STATUS_TEXT_KEY,
|
||||||
targetStateName,
|
targetStateName,
|
||||||
() -> this.pageService.getResourceService()
|
() -> this.pageService.getResourceService()
|
||||||
.examConfigStatusResources(false))
|
.examConfigStatusResourcesAll())
|
||||||
.readonly(readonly));
|
.readonly(readonly));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
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.EntityProcessingReport;
|
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||||
|
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.ExamConfigurationMap;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
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.ConfigKey;
|
||||||
|
@ -173,6 +174,16 @@ public class SEBExamConfigForm implements TemplateComposer {
|
||||||
.call()
|
.call()
|
||||||
.map(names -> names != null && !names.isEmpty())
|
.map(names -> names != null && !names.isEmpty())
|
||||||
.getOr(Boolean.FALSE);
|
.getOr(Boolean.FALSE);
|
||||||
|
final boolean hasRunningExam = isAttachedToExam && this.restService
|
||||||
|
.getBuilder(GetExamConfigMappingsPage.class)
|
||||||
|
.withQueryParam(ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())
|
||||||
|
.call()
|
||||||
|
.map(res -> res.content
|
||||||
|
.stream()
|
||||||
|
.filter(map -> map.examStatus == ExamStatus.RUNNING)
|
||||||
|
.findAny()
|
||||||
|
.isPresent())
|
||||||
|
.getOr(false);
|
||||||
|
|
||||||
// new PageContext with actual EntityKey
|
// new PageContext with actual EntityKey
|
||||||
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
|
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
|
||||||
|
@ -223,7 +234,7 @@ public class SEBExamConfigForm implements TemplateComposer {
|
||||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||||
FORM_STATUS_TEXT_KEY,
|
FORM_STATUS_TEXT_KEY,
|
||||||
examConfig.status.name(),
|
examConfig.status.name(),
|
||||||
() -> resourceService.examConfigStatusResources(isAttachedToExam))
|
() -> resourceService.examConfigStatusResources(isAttachedToExam, hasRunningExam))
|
||||||
.withEmptyCellSeparation(!isReadonly))
|
.withEmptyCellSeparation(!isReadonly))
|
||||||
.buildFor((isNew)
|
.buildFor((isNew)
|
||||||
? this.restService.getRestCall(NewExamConfig.class)
|
? this.restService.getRestCall(NewExamConfig.class)
|
||||||
|
@ -297,7 +308,7 @@ public class SEBExamConfigForm implements TemplateComposer {
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(formHandle::processFormSave)
|
.withExec(formHandle::processFormSave)
|
||||||
.ignoreMoveAwayFromEdit()
|
.ignoreMoveAwayFromEdit()
|
||||||
.withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle))
|
.withConfirm(() -> stateChangeConfirm(hasRunningExam, formHandle))
|
||||||
.publishIf(() -> !isReadonly)
|
.publishIf(() -> !isReadonly)
|
||||||
|
|
||||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
|
||||||
|
@ -436,17 +447,17 @@ public class SEBExamConfigForm implements TemplateComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocTextKey stateChangeConfirm(
|
private LocTextKey stateChangeConfirm(
|
||||||
final boolean isAttachedToExam,
|
final boolean hasRunningExam,
|
||||||
final FormHandle<ConfigurationNode> formHandle) {
|
final FormHandle<ConfigurationNode> formHandle) {
|
||||||
|
|
||||||
if (isAttachedToExam) {
|
if (hasRunningExam) {
|
||||||
final String fieldValue = formHandle
|
final String fieldValue = formHandle
|
||||||
.getForm()
|
.getForm()
|
||||||
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
|
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
|
||||||
|
|
||||||
if (fieldValue != null) {
|
if (fieldValue != null) {
|
||||||
final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue);
|
final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue);
|
||||||
if (state != ConfigurationStatus.IN_USE) {
|
if (state != ConfigurationStatus.IN_USE && state != ConfigurationStatus.ARCHIVED) {
|
||||||
return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED;
|
return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -471,7 +471,20 @@ public class ResourceService {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Tuple<String>> examConfigStatusResources(final boolean isAttachedToExam) {
|
public List<Tuple<String>> examConfigStatusResourcesAll() {
|
||||||
|
return Arrays.stream(ConfigurationStatus.values())
|
||||||
|
.map(type -> new Tuple3<>(
|
||||||
|
type.name(),
|
||||||
|
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name()),
|
||||||
|
Utils.formatLineBreaks(this.i18nSupport.getText(
|
||||||
|
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name())
|
||||||
|
+ Constants.TOOLTIP_TEXT_KEY_SUFFIX,
|
||||||
|
StringUtils.EMPTY))))
|
||||||
|
.sorted(RESOURCE_COMPARATOR)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tuple<String>> examConfigStatusResources(final boolean isAttachedToExam, final boolean hasRunningExam) {
|
||||||
return Arrays.stream(ConfigurationStatus.values())
|
return Arrays.stream(ConfigurationStatus.values())
|
||||||
.filter(status -> {
|
.filter(status -> {
|
||||||
if (isAttachedToExam) {
|
if (isAttachedToExam) {
|
||||||
|
@ -480,6 +493,7 @@ public class ResourceService {
|
||||||
return status != ConfigurationStatus.IN_USE;
|
return status != ConfigurationStatus.IN_USE;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.filter(status -> !hasRunningExam || status != ConfigurationStatus.ARCHIVED)
|
||||||
.map(type -> new Tuple3<>(
|
.map(type -> new Tuple3<>(
|
||||||
type.name(),
|
type.name(),
|
||||||
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name()),
|
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name()),
|
||||||
|
|
|
@ -442,6 +442,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
||||||
(exam != null) ? exam.description : null,
|
(exam != null) ? exam.description : null,
|
||||||
(exam != null) ? exam.startTime : null,
|
(exam != null) ? exam.startTime : null,
|
||||||
(exam != null) ? exam.type : ExamType.UNDEFINED,
|
(exam != null) ? exam.type : ExamType.UNDEFINED,
|
||||||
|
(exam != null) ? exam.status : null,
|
||||||
record.getConfigurationNodeId(),
|
record.getConfigurationNodeId(),
|
||||||
record.getUserNames(),
|
record.getUserNames(),
|
||||||
record.getEncryptSecret(),
|
record.getEncryptSecret(),
|
||||||
|
|
|
@ -136,6 +136,7 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Result<Long> getFollowupConfigurationId(final Long examConfigNodeId) {
|
public Result<Long> getFollowupConfigurationId(final Long examConfigNodeId) {
|
||||||
return this.configurationDAO.getFollowupConfigurationId(examConfigNodeId);
|
return this.configurationDAO.getFollowupConfigurationId(examConfigNodeId);
|
||||||
}
|
}
|
||||||
|
@ -443,6 +444,20 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if changing to "In Use" check config is mapped for at least one exam
|
||||||
|
if (configurationNode.status == ConfigurationStatus.IN_USE &&
|
||||||
|
existingNode.status != ConfigurationStatus.IN_USE) {
|
||||||
|
|
||||||
|
if (this.examConfigurationMapDAO
|
||||||
|
.getExamIdsForConfigNodeId(configurationNode.id)
|
||||||
|
.getOr(Collections.emptyList())
|
||||||
|
.isEmpty()) {
|
||||||
|
throw new APIMessageException(
|
||||||
|
APIMessage.ErrorMessage.INTEGRITY_VALIDATION
|
||||||
|
.of("Exam configuration has no reference to any exam."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return configurationNode;
|
return configurationNode;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -209,7 +209,7 @@ public class ModelObjectJSONGenerator {
|
||||||
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
||||||
|
|
||||||
domainObject = new ExamConfigurationMap(
|
domainObject = new ExamConfigurationMap(
|
||||||
1L, 1L, 1L, "examName", "examDescription", DateTime.now(), ExamType.BYOD,
|
1L, 1L, 1L, "examName", "examDescription", DateTime.now(), ExamType.BYOD, ExamStatus.RUNNING,
|
||||||
1L, "userNames", "encryptSecret", "confirmEncryptSecret", "configName", "configDescription",
|
1L, "userNames", "encryptSecret", "confirmEncryptSecret", "configName", "configDescription",
|
||||||
ConfigurationStatus.IN_USE);
|
ConfigurationStatus.IN_USE);
|
||||||
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
||||||
|
|
Loading…
Reference in a new issue