SEBSERV-287 finished implementation

This commit is contained in:
anhefti 2022-04-14 12:41:08 +02:00
parent e6697dd340
commit eb46de835a
5 changed files with 108 additions and 26 deletions

View file

@ -417,6 +417,16 @@ public enum ActionDefinition {
ImageIcon.DELETE,
PageStateDefinitionImpl.EXAM_TEMPLATE_LIST,
ActionCategory.FORM),
EXAM_TEMPLATE_PROCTORING_ON(
new LocTextKey("sebserver.examtemplate.proctoring.actions.open"),
ImageIcon.VISIBILITY,
PageStateDefinitionImpl.EXAM_TEMPLATE_VIEW,
ActionCategory.FORM),
EXAM_TEMPLATE_PROCTORING_OFF(
new LocTextKey("sebserver.examtemplate.proctoring.actions.open"),
ImageIcon.VISIBILITY_OFF,
PageStateDefinitionImpl.EXAM_TEMPLATE_VIEW,
ActionCategory.FORM),
INDICATOR_TEMPLATE_NEW(
new LocTextKey("sebserver.examtemplate.indicator.action.list.new"),

View file

@ -23,6 +23,7 @@ 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.ExamTemplate;
import ch.ethz.seb.sebserver.gbl.model.exam.IndicatorTemplate;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
@ -39,10 +40,12 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteExamTemplate;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicatorTemplate;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamTemplate;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamTemplateProctoringSettings;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorTemplatePage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewExamTemplate;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExamTemplate;
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.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
@ -93,13 +96,17 @@ public class ExamTemplateForm implements TemplateComposer {
private final ResourceService resourceService;
private final WidgetFactory widgetFactory;
private final RestService restService;
private final ProctoringSettingsPopup proctoringSettingsPopup;
public ExamTemplateForm(final PageService pageService) {
public ExamTemplateForm(
final PageService pageService,
final ProctoringSettingsPopup proctoringSettingsPopup) {
this.pageService = pageService;
this.resourceService = pageService.getResourceService();
this.widgetFactory = pageService.getWidgetFactory();
this.restService = pageService.getRestService();
this.proctoringSettingsPopup = proctoringSettingsPopup;
}
@Override
@ -185,7 +192,16 @@ public class ExamTemplateForm implements TemplateComposer {
? this.restService.getRestCall(NewExamTemplate.class)
: this.restService.getRestCall(SaveExamTemplate.class));
final boolean proctoringEnabled = this.restService
.getBuilder(GetExamTemplateProctoringSettings.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.map(ProctoringServiceSettings::getEnableProctoring)
.getOr(false);
final GrantCheck userGrant = currentUser.grantCheck(EntityType.EXAM_TEMPLATE);
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(examTemplate);
final boolean modifyGrant = userGrantCheck.m();
// propagate content actions to action-pane
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
@ -210,7 +226,17 @@ public class ExamTemplateForm implements TemplateComposer {
.withExec(this::deleteExamTemplate)
.publishIf(() -> userGrant.iw() && readonly)
;
.newAction(ActionDefinition.EXAM_TEMPLATE_PROCTORING_ON)
.withEntityKey(entityKey)
.withExec(this.proctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant))
.noEventPropagation()
.publishIf(() -> proctoringEnabled && readonly)
.newAction(ActionDefinition.EXAM_TEMPLATE_PROCTORING_OFF)
.withEntityKey(entityKey)
.withExec(this.proctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant))
.noEventPropagation()
.publishIf(() -> !proctoringEnabled && readonly);
if (readonly) {

View file

@ -193,7 +193,10 @@ public class ProctoringSettingsPopup {
if (saveOk) {
final PageAction action = pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.newAction(
entityKey.entityType == EntityType.EXAM
? ActionDefinition.EXAM_VIEW_FROM_LIST
: ActionDefinition.EXAM_TEMPLATE_VIEW_FROM_LIST)
.create();
pageService.firePageEvent(

View file

@ -28,6 +28,7 @@ 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.api.JSONMapper;
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.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
@ -44,6 +45,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationNodeDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamTemplateDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamTemplateService;
@ -177,28 +179,7 @@ public class ExamTemplateServiceImpl implements ExamTemplateService {
if (examTemplate.configTemplateId != null) {
// create new exam configuration for the exam
final ConfigurationNode configurationNode = new ConfigurationNode(
null,
exam.institutionId,
examTemplate.configTemplateId,
replaceVars(this.defaultExamConfigNameTemplate, exam, examTemplate),
replaceVars(this.defaultExamConfigDescTemplate, exam, examTemplate),
ConfigurationType.EXAM_CONFIG,
exam.owner,
ConfigurationStatus.IN_USE);
final ConfigurationNode examConfig = this.configurationNodeDAO
.createNew(configurationNode)
.onError(error -> log.error(
"Failed to create exam configuration for exam: {} from template: {} examConfig: {}",
exam.name,
examTemplate.name,
configurationNode,
error))
.getOrThrow(error -> new APIMessageException(
ErrorMessage.EXAM_IMPORT_ERROR_AUTO_CONFIG,
error));
final ConfigurationNode examConfig = createOrReuseConfig(exam, examTemplate);
// map the exam configuration to the exam
this.examConfigurationMapDAO.createNew(new ExamConfigurationMap(
@ -226,6 +207,68 @@ public class ExamTemplateServiceImpl implements ExamTemplateService {
}).onError(error -> log.error("Failed to create exam configuration defined by template for exam: ", error));
}
private ConfigurationNode createOrReuseConfig(final Exam exam, final ExamTemplate examTemplate) {
final String configName = replaceVars(this.defaultExamConfigNameTemplate, exam, examTemplate);
final FilterMap filterMap = new FilterMap();
filterMap.putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, exam.institutionId.toString());
filterMap.putIfAbsent(Entity.FILTER_ATTR_NAME, configName);
// get existing config if available
final ConfigurationNode examConfig = this.configurationNodeDAO
.allMatching(filterMap)
.getOrThrow()
.stream()
.filter(res -> res.name.equals(configName))
.findFirst()
.orElse(null);
if (examConfig == null || examConfig.status != ConfigurationStatus.READY_TO_USE) {
final ConfigurationNode config = new ConfigurationNode(
null,
exam.institutionId,
examTemplate.configTemplateId,
configName,
replaceVars(this.defaultExamConfigDescTemplate, exam, examTemplate),
ConfigurationType.EXAM_CONFIG,
exam.owner,
ConfigurationStatus.IN_USE);
return this.configurationNodeDAO
.createNew(config)
.onError(error -> log.error(
"Failed to create exam configuration for exam: {} from template: {} examConfig: {}",
exam.name,
examTemplate.name,
config,
error))
.getOrThrow(error -> new APIMessageException(
ErrorMessage.EXAM_IMPORT_ERROR_AUTO_CONFIG,
error));
} else {
final ConfigurationNode config = new ConfigurationNode(
examConfig.id,
null,
null,
null,
null,
null,
null,
ConfigurationStatus.IN_USE);
return this.configurationNodeDAO
.save(config)
.onError(error -> log.error(
"Failed to save exam configuration for exam: {} from template: {} examConfig: {}",
exam.name,
examTemplate.name,
config,
error))
.getOrThrow(error -> new APIMessageException(
ErrorMessage.EXAM_IMPORT_ERROR_AUTO_CONFIG,
error));
}
}
private Result<Exam> addIndicatorsFromTemplate(final Exam exam) {
return Result.tryCatch(() -> {

View file

@ -1713,7 +1713,7 @@ sebserver.examtemplate.indicator.action.list.new=Add Indicator
sebserver.examtemplate.indicator.action.list.modify=Edit Indicator
sebserver.examtemplate.indicator.action.list.delete=Delete Indicator
sebserver.examtemplate.proctoring.actions.open=Proctoring Settings
################################
# Certificates