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;
|
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.content.activity.PageStateDefinitionImpl;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition;
|
import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition;
|
||||||
|
@ -300,12 +299,12 @@ public enum ActionDefinition {
|
||||||
ActionCategory.FORM),
|
ActionCategory.FORM),
|
||||||
EXAM_TOGGLE_TEST_RUN_ON(
|
EXAM_TOGGLE_TEST_RUN_ON(
|
||||||
new LocTextKey("sebserver.exam.action.test.run.on"),
|
new LocTextKey("sebserver.exam.action.test.run.on"),
|
||||||
ImageIcon.ARCHIVE,
|
ImageIcon.TEST_RUN_OFF,
|
||||||
PageStateDefinitionImpl.EXAM_VIEW,
|
PageStateDefinitionImpl.EXAM_VIEW,
|
||||||
ActionCategory.FORM),
|
ActionCategory.FORM),
|
||||||
EXAM_TOGGLE_TEST_RUN_OFF(
|
EXAM_TOGGLE_TEST_RUN_OFF(
|
||||||
new LocTextKey("sebserver.exam.action.test.run.off"),
|
new LocTextKey("sebserver.exam.action.test.run.off"),
|
||||||
ImageIcon.ARCHIVE,
|
ImageIcon.TEST_RUN_ON,
|
||||||
PageStateDefinitionImpl.EXAM_VIEW,
|
PageStateDefinitionImpl.EXAM_VIEW,
|
||||||
ActionCategory.FORM),
|
ActionCategory.FORM),
|
||||||
EXAM_ARCHIVE(
|
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 ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ToggleTestRun;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.joda.time.DateTime;
|
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 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_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 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 Map<String, LocTextKey> consistencyMessageMapping;
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
|
@ -232,6 +234,9 @@ public class ExamForm implements TemplateComposer {
|
||||||
if (sebRestrictionMismatch || (warnings != null && !warnings.isEmpty())) {
|
if (sebRestrictionMismatch || (warnings != null && !warnings.isEmpty())) {
|
||||||
showConsistencyChecks(warnings, sebRestrictionMismatch, formContext.getParent());
|
showConsistencyChecks(warnings, sebRestrictionMismatch, formContext.getParent());
|
||||||
}
|
}
|
||||||
|
if (exam.status == ExamStatus.TEST_RUN) {
|
||||||
|
showTestRunMessage(formContext.getParent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the default page layout with title
|
// 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(ExamSEBRestrictionSettings.PAGE_CONTEXT_ATTR_LMS_ID, String.valueOf(exam.lmsSetupId))
|
||||||
.withAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY, String.valueOf(!modifyGrant || !editable))
|
.withAttribute(PageContext.AttributeKeys.FORCE_READ_ONLY, String.valueOf(!modifyGrant || !editable))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> restrictionEnabled && sebRestrictionAvailable && readonly)
|
.publishIf(() -> restrictionEnabled && sebRestrictionAvailable)
|
||||||
|
|
||||||
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
|
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, true, this.restService))
|
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, true, this.restService))
|
||||||
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
|
.publishIf(() -> sebRestrictionAvailable && modifyGrant && !importFromQuizData && BooleanUtils.isFalse(isRestricted))
|
||||||
&& BooleanUtils.isFalse(isRestricted))
|
|
||||||
|
|
||||||
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
|
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
|
||||||
.withConfirm(() -> ACTION_MESSAGE_SEB_RESTRICTION_RELEASE)
|
.withConfirm(() -> ACTION_MESSAGE_SEB_RESTRICTION_RELEASE)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService))
|
.withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService))
|
||||||
.publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData
|
.publishIf(() -> sebRestrictionAvailable && modifyGrant && !importFromQuizData && BooleanUtils.isTrue(isRestricted))
|
||||||
&& BooleanUtils.isTrue(isRestricted))
|
|
||||||
|
|
||||||
.newAction(ActionDefinition.EXAM_PROCTORING_ON)
|
.newAction(ActionDefinition.EXAM_PROCTORING_ON)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(this.proctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
|
.withExec(this.proctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> lpEnabled && !isLight && proctoringEnabled && readonly)
|
.publishIf(() -> lpEnabled && !isLight && proctoringEnabled)
|
||||||
|
|
||||||
.newAction(ActionDefinition.EXAM_PROCTORING_OFF)
|
.newAction(ActionDefinition.EXAM_PROCTORING_OFF)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
|
@ -370,7 +373,7 @@ public class ExamForm implements TemplateComposer {
|
||||||
.withExec(
|
.withExec(
|
||||||
this.screenProctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
|
this.screenProctoringSettingsPopup.settingsFunction(this.pageService, modifyGrant && editable))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> spsFeatureEnabled && screenProctoringEnabled && readonly)
|
.publishIf(() -> spsFeatureEnabled && screenProctoringEnabled)
|
||||||
|
|
||||||
.newAction(ActionDefinition.SCREEN_PROCTORING_OFF)
|
.newAction(ActionDefinition.SCREEN_PROCTORING_OFF)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
|
@ -773,6 +776,15 @@ public class ExamForm implements TemplateComposer {
|
||||||
return (lmsSetup.getLmsType().features.contains(LmsSetup.Features.SEB_RESTRICTION));
|
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(
|
private void showConsistencyChecks(
|
||||||
final Collection<APIMessage> result,
|
final Collection<APIMessage> result,
|
||||||
final boolean sebRestrictionMismatch,
|
final boolean sebRestrictionMismatch,
|
||||||
|
|
|
@ -152,7 +152,9 @@ public class WidgetFactory {
|
||||||
BACK("back.png"),
|
BACK("back.png"),
|
||||||
SCREEN_PROC_ON("screen_proc_on.png"),
|
SCREEN_PROC_ON("screen_proc_on.png"),
|
||||||
SCREEN_PROC_OFF("screen_proc_off.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;
|
public String fileName;
|
||||||
private ImageData image = null;
|
private ImageData image = null;
|
||||||
|
|
|
@ -190,14 +190,18 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
if (event.activation == Activatable.ActivationAction.NONE) {
|
if (event.activation == Activatable.ActivationAction.NONE) {
|
||||||
if (!lmsSetup.integrationActive) {
|
if (!lmsSetup.integrationActive) {
|
||||||
applyFullLmsIntegration(lmsSetup.id)
|
applyFullLmsIntegration(lmsSetup.id)
|
||||||
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
|
.onError(error -> log.warn(
|
||||||
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
"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) {
|
} else if (event.activation == Activatable.ActivationAction.ACTIVATE) {
|
||||||
applyFullLmsIntegration(lmsSetup.id)
|
applyFullLmsIntegration(lmsSetup.id)
|
||||||
.map(data -> reapplyExistingExams(data,lmsSetup))
|
.map(data -> reapplyExistingExams(data,lmsSetup))
|
||||||
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
|
.onError(error -> log.warn(
|
||||||
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
"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) {
|
} else if (event.activation == Activatable.ActivationAction.DEACTIVATE) {
|
||||||
// remove all active exam data for involved exams before deactivate them
|
// remove all active exam data for involved exams before deactivate them
|
||||||
this.examDAO
|
this.examDAO
|
||||||
|
@ -235,7 +239,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
public void notifyConnectionConfigurationChange(final ConnectionConfigurationChangeEvent event) {
|
public void notifyConnectionConfigurationChange(final ConnectionConfigurationChangeEvent event) {
|
||||||
lmsSetupDAO.idsOfActiveWithFullIntegration(event.institutionId)
|
lmsSetupDAO.idsOfActiveWithFullIntegration(event.institutionId)
|
||||||
.flatMap(examDAO::allActiveForLMSSetup)
|
.flatMap(examDAO::allActiveForLMSSetup)
|
||||||
.onError(error -> log.error("Failed to notifyConnectionConfigurationChange: {}", error.getMessage()))
|
.onError(error -> log.error(
|
||||||
|
"Failed to notifyConnectionConfigurationChange: {}",
|
||||||
|
error.getMessage()))
|
||||||
.getOr(Collections.emptyList())
|
.getOr(Collections.emptyList())
|
||||||
.stream()
|
.stream()
|
||||||
.filter(exam -> this.needsConnectionConfigurationChange(exam, event.configId))
|
.filter(exam -> this.needsConnectionConfigurationChange(exam, event.configId))
|
||||||
|
@ -370,16 +376,22 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.flatMap(this::findExam);
|
.flatMap(this::findExam);
|
||||||
|
|
||||||
if (examResult.hasError()) {
|
if (examResult.hasError()) {
|
||||||
log.error("Failed to find exam for SEB Connection Configuration download: ", examResult.getError());
|
log.error(
|
||||||
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("Exam not found"));
|
"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 Exam exam = examResult.get();
|
||||||
|
|
||||||
final String connectionConfigId = getConnectionConfigurationId(exam);
|
final String connectionConfigId = getConnectionConfigurationId(exam);
|
||||||
if (StringUtils.isBlank(connectionConfigId)) {
|
if (StringUtils.isBlank(connectionConfigId)) {
|
||||||
log.error("Failed to verify SEB Connection Configuration id for exam: {}", exam.name);
|
log.error(
|
||||||
throw new APIMessage.APIMessageException(APIMessage.ErrorMessage.ILLEGAL_API_ARGUMENT.of("No active Connection Configuration found"));
|
"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(
|
this.connectionConfigurationService.exportSEBClientConfiguration(
|
||||||
|
@ -413,7 +425,8 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.map(all -> all.stream().filter(config -> config.configPurpose == SEBClientConfig.ConfigPurpose.START_EXAM)
|
.map(all -> all.stream().filter(config -> config.configPurpose == SEBClientConfig.ConfigPurpose.START_EXAM)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new APIMessage.APIMessageException(
|
.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)
|
.map(SEBClientConfig::getModelId)
|
||||||
.getOr(null);
|
.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
|
// check if the exam has already been imported, If so return the existing exam
|
||||||
final Result<Exam> existingExam = findExam(quizData);
|
final Result<Exam> existingExam = findExam(quizData);
|
||||||
if (!existingExam.hasError()) {
|
if (!existingExam.hasError()) {
|
||||||
// TODO do we need to check if ad-hoc account exists and if not, create one?
|
|
||||||
return existingExam.get();
|
return existingExam.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +538,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
final Integer active = this.clientConnectionDAO
|
final Integer active = this.clientConnectionDAO
|
||||||
.getAllActiveConnectionTokens(exam.id)
|
.getAllActiveConnectionTokens(exam.id)
|
||||||
.map(Collection::size)
|
.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);
|
.getOr(1);
|
||||||
|
|
||||||
if (active == null || active == 0) {
|
if (active == null || active == 0) {
|
||||||
|
@ -570,9 +584,13 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
? null
|
? null
|
||||||
: exam.examTemplateId != null
|
: exam.examTemplateId != null
|
||||||
? String.valueOf(exam.examTemplateId)
|
? String.valueOf(exam.examTemplateId)
|
||||||
: "0";
|
: "0"; // no selection on Moodle site
|
||||||
final String quitPassword = deletion ? null : examConfigurationValueService.getQuitPassword(exam.id);
|
final String quitPassword = deletion
|
||||||
final String quitLink = deletion ? null : examConfigurationValueService.getQuitLink(exam.id);
|
? null
|
||||||
|
: examConfigurationValueService.getQuitPassword(exam.id);
|
||||||
|
final String quitLink = deletion
|
||||||
|
? null
|
||||||
|
: examConfigurationValueService.getQuitLink(exam.id);
|
||||||
|
|
||||||
final ExamData examData = new ExamData(
|
final ExamData examData = new ExamData(
|
||||||
lmsUUID,
|
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) {
|
// private Exam applyConnectionConfiguration(final Exam exam) {
|
||||||
// return lmsAPITemplateCacheService
|
// return lmsAPITemplateCacheService
|
||||||
// .getLmsAPITemplate(exam.lmsSetupId)
|
// .getLmsAPITemplate(exam.lmsSetupId)
|
||||||
|
@ -689,14 +711,18 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
private Exam logExamCreated(final Exam exam) {
|
private Exam logExamCreated(final Exam exam) {
|
||||||
this.userActivityLogDAO
|
this.userActivityLogDAO
|
||||||
.logCreate(exam)
|
.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;
|
return exam;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exam logExamDeleted(final Exam exam) {
|
private Exam logExamDeleted(final Exam exam) {
|
||||||
this.userActivityLogDAO
|
this.userActivityLogDAO
|
||||||
.logDelete(exam)
|
.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;
|
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=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.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
|
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