SEBSERV-419

This commit is contained in:
anhefti 2024-07-02 13:43:07 +02:00
parent 900bbfe5f4
commit c0ead99e2b
7 changed files with 68 additions and 29 deletions

View file

@ -8,7 +8,6 @@
package ch.ethz.seb.sebserver.gui.content.action;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gui.content.activity.PageStateDefinitionImpl;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition;
@ -300,12 +299,12 @@ public enum ActionDefinition {
ActionCategory.FORM),
EXAM_TOGGLE_TEST_RUN_ON(
new LocTextKey("sebserver.exam.action.test.run.on"),
ImageIcon.ARCHIVE,
ImageIcon.TEST_RUN_OFF,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_TOGGLE_TEST_RUN_OFF(
new LocTextKey("sebserver.exam.action.test.run.off"),
ImageIcon.ARCHIVE,
ImageIcon.TEST_RUN_ON,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_ARCHIVE(

View file

@ -22,6 +22,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSe
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ToggleTestRun;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.joda.time.DateTime;
@ -112,6 +113,7 @@ public class ExamForm implements TemplateComposer {
private final static LocTextKey CONSISTENCY_MESSAGE_SEB_RESTRICTION_MISMATCH = new LocTextKey("sebserver.exam.consistencyseb-restriction-mismatch");
private final static LocTextKey AUTO_GEN_CONFIG_ERROR_TITLE = new LocTextKey("sebserver.exam.autogen.error.config.title");
private final static LocTextKey AUTO_GEN_CONFIG_ERROR_TEXT = new LocTextKey("sebserver.exam.autogen.error.config.text");
private final static LocTextKey TEST_RUN_ENABLED_NOTE = new LocTextKey("sebserver.exam.test.run.enabled.note");
private final Map<String, LocTextKey> consistencyMessageMapping;
private final PageService pageService;
@ -232,6 +234,9 @@ public class ExamForm implements TemplateComposer {
if (sebRestrictionMismatch || (warnings != null && !warnings.isEmpty())) {
showConsistencyChecks(warnings, sebRestrictionMismatch, formContext.getParent());
}
if (exam.status == ExamStatus.TEST_RUN) {
showTestRunMessage(formContext.getParent());
}
}
// the default page layout with title
@ -338,26 +343,24 @@ public class ExamForm implements TemplateComposer {
.withAttribute(ExamSEBRestrictionSettings.PAGE_CONTEXT_ATTR_LMS_ID, String.valueOf(exam.lmsSetupId))
.withAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY, String.valueOf(!modifyGrant || !editable))
.noEventPropagation()
.publishIf(() -> restrictionEnabled && sebRestrictionAvailable && readonly)
.publishIf(() -> restrictionEnabled && sebRestrictionAvailable)
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
.withEntityKey(entityKey)
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, true, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isFalse(isRestricted))
.publishIf(() -> sebRestrictionAvailable && modifyGrant && !importFromQuizData && BooleanUtils.isFalse(isRestricted))
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
.withConfirm(() -> ACTION_MESSAGE_SEB_RESTRICTION_RELEASE)
.withEntityKey(entityKey)
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService))
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
&& BooleanUtils.isTrue(isRestricted))
.publishIf(() -> sebRestrictionAvailable && modifyGrant && !importFromQuizData && BooleanUtils.isTrue(isRestricted))
.newAction(ActionDefinition.EXAM_PROCTORING_ON)
.withEntityKey(entityKey)
.withExec(this.proctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
.noEventPropagation()
.publishIf(() -> lpEnabled && !isLight && proctoringEnabled && readonly)
.publishIf(() -> lpEnabled && !isLight && proctoringEnabled)
.newAction(ActionDefinition.EXAM_PROCTORING_OFF)
.withEntityKey(entityKey)
@ -370,7 +373,7 @@ public class ExamForm implements TemplateComposer {
.withExec(
this.screenProctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
.noEventPropagation()
.publishIf(() -> spsFeatureEnabled && screenProctoringEnabled && readonly)
.publishIf(() -> spsFeatureEnabled && screenProctoringEnabled)
.newAction(ActionDefinition.SCREEN_PROCTORING_OFF)
.withEntityKey(entityKey)
@ -773,6 +776,15 @@ public class ExamForm implements TemplateComposer {
return (lmsSetup.getLmsType().features.contains(LmsSetup.Features.SEB_RESTRICTION));
}
private void showTestRunMessage(final Composite parent) {
final Composite notePanel = this.widgetFactory.createWarningPanel(parent);
notePanel.setData(RWT.CUSTOM_VARIANT, CustomVariant.NOTE.key);
this.widgetFactory.labelLocalized(
notePanel,
CustomVariant.TITLE_LABEL,
TEST_RUN_ENABLED_NOTE);
}
private void showConsistencyChecks(
final Collection<APIMessage> result,
final boolean sebRestrictionMismatch,

View file

@ -152,7 +152,9 @@ public class WidgetFactory {
BACK("back.png"),
SCREEN_PROC_ON("screen_proc_on.png"),
SCREEN_PROC_OFF("screen_proc_off.png"),
ADD_EXAM("add_exam.png");
ADD_EXAM("add_exam.png"),
TEST_RUN_ON("testRunOn.png"),
TEST_RUN_OFF("testRunOff.png");
public String fileName;
private ImageData image = null;

View file

@ -190,14 +190,18 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
if (event.activation == Activatable.ActivationAction.NONE) {
if (!lmsSetup.integrationActive) {
applyFullLmsIntegration(lmsSetup.id)
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
.onError(error -> log.warn(
"Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
.onSuccess(data -> log.debug(
"Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
}
} else if (event.activation == Activatable.ActivationAction.ACTIVATE) {
applyFullLmsIntegration(lmsSetup.id)
.map(data -> reapplyExistingExams(data,lmsSetup))
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
.onError(error -> log.warn(
"Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
.onSuccess(data -> log.debug(
"Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
} else if (event.activation == Activatable.ActivationAction.DEACTIVATE) {
// remove all active exam data for involved exams before deactivate them
this.examDAO
@ -235,7 +239,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
public void notifyConnectionConfigurationChange(final ConnectionConfigurationChangeEvent event) {
lmsSetupDAO.idsOfActiveWithFullIntegration(event.institutionId)
.flatMap(examDAO::allActiveForLMSSetup)
.onError(error -> log.error("Failed to notifyConnectionConfigurationChange: {}", error.getMessage()))
.onError(error -> log.error(
"Failed to notifyConnectionConfigurationChange: {}",
error.getMessage()))
.getOr(Collections.emptyList())
.stream()
.filter(exam -> this.needsConnectionConfigurationChange(exam, event.configId))
@ -370,16 +376,22 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
.flatMap(this::findExam);
if (examResult.hasError()) {
log.error("Failed to find exam for SEB Connection Configuration download: ", examResult.getError());
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("Exam not found"));
log.error(
"Failed to find exam for SEB Connection Configuration download: ",
examResult.getError());
throw new APIMessage.APIMessageException(
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("Exam not found"));
}
final Exam exam = examResult.get();
final String connectionConfigId = getConnectionConfigurationId(exam);
if (StringUtils.isBlank(connectionConfigId)) {
log.error("Failed to verify SEB Connection Configuration id for exam: {}", exam.name);
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
log.error(
"Failed to verify SEB Connection Configuration id for exam: {}",
exam.name);
throw new APIMessage.APIMessageException(
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
}
this.connectionConfigurationService.exportSEBClientConfiguration(
@ -413,7 +425,8 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
.map(all -> all.stream().filter(config -> config.configPurpose == SEBClientConfig.ConfigPurpose.START_EXAM)
.findFirst()
.orElseThrow(() -> new APIMessage.APIMessageException(
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"))))
APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of(
"No active Connection Configuration found"))))
.map(SEBClientConfig::getModelId)
.getOr(null);
}
@ -487,7 +500,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
// check if the exam has already been imported, If so return the existing exam
final Result<Exam> existingExam = findExam(quizData);
if (!existingExam.hasError()) {
// TODO do we need to check if ad-hoc account exists and if not, create one?
return existingExam.get();
}
@ -526,7 +538,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
final Integer active = this.clientConnectionDAO
.getAllActiveConnectionTokens(exam.id)
.map(Collection::size)
.onError(error -> log.warn("Failed to get active access tokens for exam: {}", error.getMessage()))
.onError(error -> log.warn(
"Failed to get active access tokens for exam: {}",
error.getMessage()))
.getOr(1);
if (active == null || active == 0) {
@ -570,9 +584,13 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
? null
: exam.examTemplateId != null
? String.valueOf(exam.examTemplateId)
: "0";
final String quitPassword = deletion ? null : examConfigurationValueService.getQuitPassword(exam.id);
final String quitLink = deletion ? null : examConfigurationValueService.getQuitLink(exam.id);
: "0"; // no selection on Moodle site
final String quitPassword = deletion
? null
: examConfigurationValueService.getQuitPassword(exam.id);
final String quitLink = deletion
? null
: examConfigurationValueService.getQuitLink(exam.id);
final ExamData examData = new ExamData(
lmsUUID,
@ -620,6 +638,10 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
}
}
// Note: We decided that Moodle gets the Connection Configuration from SEB Server instead of SEB Server
// sending the Connection Configuration to Moodle. Code on SEB Server site and Moodle function still
// remains here for the case its need in the future.
//
// private Exam applyConnectionConfiguration(final Exam exam) {
// return lmsAPITemplateCacheService
// .getLmsAPITemplate(exam.lmsSetupId)
@ -689,14 +711,18 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
private Exam logExamCreated(final Exam exam) {
this.userActivityLogDAO
.logCreate(exam)
.onError(error -> log.warn("Failed to log exam creation from LMS: {}", error.getMessage()));
.onError(error -> log.warn(
"Failed to log exam creation from LMS: {}",
error.getMessage()));
return exam;
}
private Exam logExamDeleted(final Exam exam) {
this.userActivityLogDAO
.logDelete(exam)
.onError(error -> log.warn("Failed to log exam deletion from LMS: {}", error.getMessage()));
.onError(error -> log.warn(
"Failed to log exam deletion from LMS: {}",
error.getMessage()));
return exam;
}

View file

@ -926,7 +926,7 @@ sebserver.exam.sps.form.collect.strategy=Grouping Strategy
sebserver.exam.sps.form.saveSettings=Save Settings
sebserver.exam.sps.form.saveSettings.error=SEB Server is not able to connect to bundled Screen Proctoring service within the given Service URL.<br/>This probably relies on a incorrect SEB Server setup.<br/><br/>Please make sure your SEB Server setup uses the correct URL mappings or contact a system administrator.
sebserver.exam.test.run.enabled.note=Exam Test Run is currently enabled. To disable please use "Disable Test Run"
sebserver.exam.signaturekey.action.edit=App Signature Key

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B