SEBSERV-419
This commit is contained in:
parent
900bbfe5f4
commit
c0ead99e2b
7 changed files with 68 additions and 29 deletions
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
src/main/resources/static/images/testRunOff.png
Normal file
BIN
src/main/resources/static/images/testRunOff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 B |
BIN
src/main/resources/static/images/testRunOn.png
Normal file
BIN
src/main/resources/static/images/testRunOn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 367 B |
Loading…
Reference in a new issue