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.Entity;
|
||||
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.sebconfig.ConfigurationNode.ConfigurationStatus;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
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 FILTER_ATTR_EXAM_ID = "examId";
|
||||
|
@ -60,6 +63,9 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
@JsonProperty(EXAM.ATTR_TYPE)
|
||||
public final ExamType examType;
|
||||
|
||||
@JsonProperty(ARR_EXAM_STATUS)
|
||||
public final ExamStatus examStatus;
|
||||
|
||||
@NotNull(message = "examConfigurationMap:configurationNodeId:notNull")
|
||||
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID)
|
||||
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_START_TIME) final DateTime examStartTime,
|
||||
@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_USER_NAMES) final String userNames,
|
||||
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
|
||||
|
@ -106,6 +113,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
this.examDescription = examDescription;
|
||||
this.examStartTime = examStartTime;
|
||||
this.examType = examType;
|
||||
this.examStatus = examStatus;
|
||||
this.configurationNodeId = configurationNodeId;
|
||||
this.userNames = userNames;
|
||||
this.encryptSecret = encryptSecret;
|
||||
|
@ -125,6 +133,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
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.examStatus = postParams.getEnum(ARR_EXAM_STATUS, ExamStatus.class);
|
||||
|
||||
this.configurationNodeId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
|
||||
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.examStartTime = null;
|
||||
this.examType = null;
|
||||
this.examStatus = null;
|
||||
this.configurationNodeId = configurationNodeId;
|
||||
this.userNames = userNames;
|
||||
this.encryptSecret = null;
|
||||
|
@ -205,6 +215,10 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
return this.examType;
|
||||
}
|
||||
|
||||
public ExamStatus getExamStatus() {
|
||||
return this.examStatus;
|
||||
}
|
||||
|
||||
public Long getConfigurationNodeId() {
|
||||
return this.configurationNodeId;
|
||||
}
|
||||
|
@ -250,6 +264,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
this.examDescription,
|
||||
this.examStartTime,
|
||||
this.examType,
|
||||
this.examStatus,
|
||||
this.configurationNodeId,
|
||||
this.userNames,
|
||||
Constants.EMPTY_NOTE,
|
||||
|
@ -296,7 +311,7 @@ public final class ExamConfigurationMap implements GrantEntity {
|
|||
|
||||
public static ExamConfigurationMap createNew(final Exam exam) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ public class SEBExamConfigBatchStateChangePopup extends AbstractBatchActionWizar
|
|||
FORM_STATUS_TEXT_KEY,
|
||||
targetStateName,
|
||||
() -> this.pageService.getResourceService()
|
||||
.examConfigStatusResources(false))
|
||||
.examConfigStatusResourcesAll())
|
||||
.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.EntityKey;
|
||||
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.QuizData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
|
||||
|
@ -173,6 +174,16 @@ public class SEBExamConfigForm implements TemplateComposer {
|
|||
.call()
|
||||
.map(names -> names != null && !names.isEmpty())
|
||||
.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
|
||||
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
|
||||
|
@ -223,7 +234,7 @@ public class SEBExamConfigForm implements TemplateComposer {
|
|||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
FORM_STATUS_TEXT_KEY,
|
||||
examConfig.status.name(),
|
||||
() -> resourceService.examConfigStatusResources(isAttachedToExam))
|
||||
() -> resourceService.examConfigStatusResources(isAttachedToExam, hasRunningExam))
|
||||
.withEmptyCellSeparation(!isReadonly))
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewExamConfig.class)
|
||||
|
@ -297,7 +308,7 @@ public class SEBExamConfigForm implements TemplateComposer {
|
|||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle))
|
||||
.withConfirm(() -> stateChangeConfirm(hasRunningExam, formHandle))
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
|
||||
|
@ -436,17 +447,17 @@ public class SEBExamConfigForm implements TemplateComposer {
|
|||
}
|
||||
|
||||
private LocTextKey stateChangeConfirm(
|
||||
final boolean isAttachedToExam,
|
||||
final boolean hasRunningExam,
|
||||
final FormHandle<ConfigurationNode> formHandle) {
|
||||
|
||||
if (isAttachedToExam) {
|
||||
if (hasRunningExam) {
|
||||
final String fieldValue = formHandle
|
||||
.getForm()
|
||||
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
|
||||
|
||||
if (fieldValue != null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -471,7 +471,20 @@ public class ResourceService {
|
|||
.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())
|
||||
.filter(status -> {
|
||||
if (isAttachedToExam) {
|
||||
|
@ -480,6 +493,7 @@ public class ResourceService {
|
|||
return status != ConfigurationStatus.IN_USE;
|
||||
}
|
||||
})
|
||||
.filter(status -> !hasRunningExam || status != ConfigurationStatus.ARCHIVED)
|
||||
.map(type -> new Tuple3<>(
|
||||
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.startTime : null,
|
||||
(exam != null) ? exam.type : ExamType.UNDEFINED,
|
||||
(exam != null) ? exam.status : null,
|
||||
record.getConfigurationNodeId(),
|
||||
record.getUserNames(),
|
||||
record.getEncryptSecret(),
|
||||
|
|
|
@ -136,6 +136,7 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Long> getFollowupConfigurationId(final Long 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;
|
||||
|
||||
});
|
||||
|
|
|
@ -209,7 +209,7 @@ public class ModelObjectJSONGenerator {
|
|||
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
||||
|
||||
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",
|
||||
ConfigurationStatus.IN_USE);
|
||||
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
||||
|
|
Loading…
Reference in a new issue