SEBSERV-487 preparation
This commit is contained in:
parent
c861967f5b
commit
3fa60445e0
14 changed files with 72 additions and 27 deletions
|
@ -14,20 +14,33 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
|
||||||
|
|
||||||
public interface FeatureService {
|
public interface FeatureService {
|
||||||
|
|
||||||
String SCREEN_PROCTORING_FEATURE_NAME = "seb.screenProctoring";
|
|
||||||
String INSTITUTION_FEATURE_NAME = "admin.institution";
|
|
||||||
String REMOTE_PROCTORING_FEATURE_NAME = "seb.remoteProctoring";
|
|
||||||
String TEST_LMS_FEATURE_NAME = "lms.testLMS";
|
|
||||||
String EXAM_NO_LMS_FEATURE_NAME = "exam.noLMS";
|
|
||||||
|
|
||||||
String FEATURE_SETTINGS_PREFIX = "sebserver.feature.";
|
String FEATURE_SETTINGS_PREFIX = "sebserver.feature.";
|
||||||
|
|
||||||
|
enum ConfigurableFeature {
|
||||||
|
SCREEN_PROCTORING("seb.screenProctoring"),
|
||||||
|
INSTITUTION("admin.institution"),
|
||||||
|
REMOTE_PROCTORING("seb.remoteProctoring"),
|
||||||
|
TEST_LMS("lms.testLMS"),
|
||||||
|
EXAM_NO_LMS("exam.noLMS"),
|
||||||
|
LIGHT_SETUP("setup.light")
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
final String namespace;
|
||||||
|
|
||||||
|
ConfigurableFeature(final String namespace) {
|
||||||
|
this.namespace = namespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEnabled(ConfigurableFeature feature);
|
||||||
|
|
||||||
boolean isEnabled(LmsType LmsType);
|
boolean isEnabled(LmsType LmsType);
|
||||||
|
|
||||||
boolean isEnabled(ProctoringServerType proctoringServerType);
|
boolean isEnabled(ProctoringServerType proctoringServerType);
|
||||||
|
|
||||||
boolean isEnabled(CollectingStrategy collectingRoomStrategy);
|
boolean isEnabled(CollectingStrategy collectingRoomStrategy);
|
||||||
|
|
||||||
boolean isEnabled(String featureSuffix);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,9 +56,9 @@ public class FeatureServiceImpl implements FeatureService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(final String featureSuffix) {
|
public boolean isEnabled(final ConfigurableFeature feature) {
|
||||||
return this.environment.getProperty(toConfigName(
|
return this.environment.getProperty(toConfigName(
|
||||||
FEATURE_SETTINGS_PREFIX + featureSuffix + ".enabled"),
|
FEATURE_SETTINGS_PREFIX + feature.namespace + ".enabled"),
|
||||||
Boolean.class,
|
Boolean.class,
|
||||||
Boolean.FALSE);
|
Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,13 @@ public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Webservice admin API basic access: --" + webServiceAPIBasicAccess + "--");
|
SEBServerInit.INIT_LOGGER.info("----> Webservice admin API basic access: --" + webServiceAPIBasicAccess + "--");
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
|
if (this.guiServiceInfo.isDistributedSetup()) {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> SEB Server GUI running on distributed setup");
|
||||||
|
} else {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> SEB Server GUI running on bundled setup");
|
||||||
|
}
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *** GUI Service successfully successfully started up! ***");
|
SEBServerInit.INIT_LOGGER.info("----> *** GUI Service successfully successfully started up! ***");
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui;
|
package ch.ethz.seb.sebserver.gui;
|
||||||
|
|
||||||
|
import static ch.ethz.seb.sebserver.gbl.FeatureService.ConfigurableFeature.LIGHT_SETUP;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.FeatureService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -32,7 +35,10 @@ public class GuiServiceInfo {
|
||||||
private final boolean distributedSetup;
|
private final boolean distributedSetup;
|
||||||
private final boolean multilingualGUI;
|
private final boolean multilingualGUI;
|
||||||
|
|
||||||
|
public final FeatureService featureService;
|
||||||
|
|
||||||
public GuiServiceInfo(
|
public GuiServiceInfo(
|
||||||
|
final FeatureService featureService,
|
||||||
@Value("${sebserver.version:--}") final String sebServerVersion,
|
@Value("${sebserver.version:--}") final String sebServerVersion,
|
||||||
@Value("${server.address}") final String internalServer,
|
@Value("${server.address}") final String internalServer,
|
||||||
@Value("${server.port}") final String internalPort,
|
@Value("${server.port}") final String internalPort,
|
||||||
|
@ -44,6 +50,7 @@ public class GuiServiceInfo {
|
||||||
@Value("${sebserver.webservice.distributed:false}") final boolean distributedSetup,
|
@Value("${sebserver.webservice.distributed:false}") final boolean distributedSetup,
|
||||||
@Value("${sebserver.gui.multilingual:false}") final boolean multilingualGUI) {
|
@Value("${sebserver.gui.multilingual:false}") final boolean multilingualGUI) {
|
||||||
|
|
||||||
|
this.featureService = featureService;
|
||||||
if (StringUtils.isBlank(externalScheme)) {
|
if (StringUtils.isBlank(externalScheme)) {
|
||||||
throw new RuntimeException("Missing mandatory inital parameter sebserver.gui.http.external.servername");
|
throw new RuntimeException("Missing mandatory inital parameter sebserver.gui.http.external.servername");
|
||||||
}
|
}
|
||||||
|
@ -81,6 +88,10 @@ public class GuiServiceInfo {
|
||||||
this.multilingualGUI = multilingualGUI;
|
this.multilingualGUI = multilingualGUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLightSetup() {
|
||||||
|
return this.featureService.isEnabled(LIGHT_SETUP);
|
||||||
|
}
|
||||||
|
|
||||||
public String getExternalScheme() {
|
public String getExternalScheme() {
|
||||||
return this.externalScheme;
|
return this.externalScheme;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
private String guiEntryPoint;
|
private String guiEntryPoint;
|
||||||
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}")
|
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}")
|
||||||
private String remoteProctoringEndpoint;
|
private String remoteProctoringEndpoint;
|
||||||
@Value("${sebserver.gui.remote.proctoring.api-servler.endpoint:/remote-view-servlet}")
|
@Value("${sebserver.gui.remote.proctoring.api-servlet.endpoint:/remote-view-servlet}")
|
||||||
private String remoteProctoringViewServletEndpoint;
|
private String remoteProctoringViewServletEndpoint;
|
||||||
@Value("${springdoc.api-docs.enabled:false}")
|
@Value("${springdoc.api-docs.enabled:false}")
|
||||||
private boolean springDocsAPIEnabled;
|
private boolean springDocsAPIEnabled;
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class RAPSpringConfig {
|
||||||
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}")
|
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}")
|
||||||
private String remoteProctoringEndpoint;
|
private String remoteProctoringEndpoint;
|
||||||
|
|
||||||
@Value("${sebserver.gui.remote.proctoring.api-servler.endpoint:/remote-view-servlet}")
|
@Value("${sebserver.gui.remote.proctoring.api-servlet.endpoint:/remote-view-servlet}")
|
||||||
private String remoteProctoringViewServletEndpoint;
|
private String remoteProctoringViewServletEndpoint;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.content.exam;
|
package ch.ethz.seb.sebserver.gui.content.exam;
|
||||||
|
|
||||||
|
import static ch.ethz.seb.sebserver.gbl.FeatureService.ConfigurableFeature.SCREEN_PROCTORING;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -17,6 +19,7 @@ import java.util.Objects;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.FeatureService;
|
||||||
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.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
@ -27,7 +30,6 @@ import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.FeatureService;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||||
|
@ -419,7 +421,7 @@ public class ExamForm implements TemplateComposer {
|
||||||
.map(ProctoringServiceSettings::getEnableProctoring)
|
.map(ProctoringServiceSettings::getEnableProctoring)
|
||||||
.getOr(false);
|
.getOr(false);
|
||||||
|
|
||||||
final boolean spsFeatureEnabled = this.featureService.isEnabled(FeatureService.SCREEN_PROCTORING_FEATURE_NAME);
|
final boolean spsFeatureEnabled = this.featureService.isEnabled(SCREEN_PROCTORING);
|
||||||
final boolean screenProctoringEnabled = spsFeatureEnabled && !importFromQuizData && this.restService
|
final boolean screenProctoringEnabled = spsFeatureEnabled && !importFromQuizData && this.restService
|
||||||
.getBuilder(GetScreenProctoringSettings.class)
|
.getBuilder(GetScreenProctoringSettings.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.content.monitoring;
|
package ch.ethz.seb.sebserver.gui.content.monitoring;
|
||||||
|
|
||||||
|
import static ch.ethz.seb.sebserver.gbl.FeatureService.ConfigurableFeature.SCREEN_PROCTORING;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -319,7 +321,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
final PageActionBuilder actionBuilder = this.pageService
|
final PageActionBuilder actionBuilder = this.pageService
|
||||||
.pageActionBuilder(pageContext.clearEntityKeys());
|
.pageActionBuilder(pageContext.clearEntityKeys());
|
||||||
|
|
||||||
final boolean spsFeatureEnabled = this.featureService.isEnabled(FeatureService.SCREEN_PROCTORING_FEATURE_NAME);
|
final boolean spsFeatureEnabled = this.featureService.isEnabled(SCREEN_PROCTORING);
|
||||||
final boolean proctoringEnabled = spsFeatureEnabled &&
|
final boolean proctoringEnabled = spsFeatureEnabled &&
|
||||||
proctoringSettings != null &&
|
proctoringSettings != null &&
|
||||||
BooleanUtils.toBoolean(proctoringSettings.enableProctoring);
|
BooleanUtils.toBoolean(proctoringSettings.enableProctoring);
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class JitsiMeetProctoringView extends AbstractProctoringView {
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final GuiServiceInfo guiServiceInfo,
|
final GuiServiceInfo guiServiceInfo,
|
||||||
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}") final String remoteProctoringEndpoint,
|
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}") final String remoteProctoringEndpoint,
|
||||||
@Value("${sebserver.gui.remote.proctoring.api-servler.endpoint:/remote-view-servlet}") final String remoteProctoringViewServletEndpoint) {
|
@Value("${sebserver.gui.remote.proctoring.api-servlet.endpoint:/remote-view-servlet}") final String remoteProctoringViewServletEndpoint) {
|
||||||
|
|
||||||
super(pageService, guiServiceInfo, remoteProctoringEndpoint, remoteProctoringViewServletEndpoint);
|
super(pageService, guiServiceInfo, remoteProctoringEndpoint, remoteProctoringViewServletEndpoint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ZoomProctoringView extends AbstractProctoringView {
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final GuiServiceInfo guiServiceInfo,
|
final GuiServiceInfo guiServiceInfo,
|
||||||
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}") final String remoteProctoringEndpoint,
|
@Value("${sebserver.gui.remote.proctoring.entrypoint:/remote-proctoring}") final String remoteProctoringEndpoint,
|
||||||
@Value("${sebserver.gui.remote.proctoring.api-servler.endpoint:/remote-view-servlet}") final String remoteProctoringViewServletEndpoint) {
|
@Value("${sebserver.gui.remote.proctoring.api-servlet.endpoint:/remote-view-servlet}") final String remoteProctoringViewServletEndpoint) {
|
||||||
|
|
||||||
super(pageService, guiServiceInfo, remoteProctoringEndpoint, remoteProctoringViewServletEndpoint);
|
super(pageService, guiServiceInfo, remoteProctoringEndpoint, remoteProctoringViewServletEndpoint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice;
|
package ch.ethz.seb.sebserver.webservice;
|
||||||
|
|
||||||
|
import static ch.ethz.seb.sebserver.gbl.FeatureService.ConfigurableFeature.LIGHT_SETUP;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -18,6 +20,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.FeatureService;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.SPSAPIAccessData;
|
import ch.ethz.seb.sebserver.gbl.model.exam.SPSAPIAccessData;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -82,13 +85,17 @@ public class WebserviceInfo {
|
||||||
@Value("${sebserver.webservice.api.exam.accessTokenValiditySeconds:43200}")
|
@Value("${sebserver.webservice.api.exam.accessTokenValiditySeconds:43200}")
|
||||||
private int examAPITokenValiditySeconds;
|
private int examAPITokenValiditySeconds;
|
||||||
|
|
||||||
|
public final FeatureService featureService;
|
||||||
|
|
||||||
private final ScreenProctoringServiceBundle screenProctoringServiceBundle;
|
private final ScreenProctoringServiceBundle screenProctoringServiceBundle;
|
||||||
|
|
||||||
public WebserviceInfo(
|
public WebserviceInfo(
|
||||||
final WebserviceInfoDAO webserviceInfoDAO,
|
final WebserviceInfoDAO webserviceInfoDAO,
|
||||||
final Environment environment,
|
final Environment environment,
|
||||||
final Cryptor cryptor) {
|
final Cryptor cryptor,
|
||||||
|
final FeatureService featureService) {
|
||||||
|
|
||||||
|
this.featureService = featureService;
|
||||||
this.webserviceInfoDAO = webserviceInfoDAO;
|
this.webserviceInfoDAO = webserviceInfoDAO;
|
||||||
this.sebServerVersion = environment.getRequiredProperty(VERSION_KEY);
|
this.sebServerVersion = environment.getRequiredProperty(VERSION_KEY);
|
||||||
this.testProperty = environment.getProperty(WEB_SERVICE_TEST_PROPERTY, "NOT_AVAILABLE");
|
this.testProperty = environment.getProperty(WEB_SERVICE_TEST_PROPERTY, "NOT_AVAILABLE");
|
||||||
|
@ -173,6 +180,10 @@ public class WebserviceInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLightSetup() {
|
||||||
|
return this.featureService.isEnabled(LIGHT_SETUP);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMaster() {
|
public boolean isMaster() {
|
||||||
return this.isMaster;
|
return this.isMaster;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,11 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
this.environment.getProperty("sebserver.webservice.distributed.connectionUpdate", "2000"));
|
this.environment.getProperty("sebserver.webservice.distributed.connectionUpdate", "2000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.webserviceInfo.isLightSetup()) {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> SEB Server light setup enabled");
|
||||||
|
}
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Working with ping service: {}",
|
SEBServerInit.INIT_LOGGER.info("----> Working with ping service: {}",
|
||||||
this.environment.getProperty("sebserver.webservice.ping.service.strategy"));
|
this.environment.getProperty("sebserver.webservice.ping.service.strategy"));
|
||||||
|
|
|
@ -41,13 +41,6 @@ sebserver.gui.seb.exam.config.download.filename=SEBExamSettings.seb
|
||||||
sebserver.gui.proctoring.zoom.websdk.version=2.8.0
|
sebserver.gui.proctoring.zoom.websdk.version=2.8.0
|
||||||
sebserver.gui.filter.date.from.years=2
|
sebserver.gui.filter.date.from.years=2
|
||||||
|
|
||||||
# remote proctoring
|
|
||||||
sebserver.gui.remote.proctoring.entrypoint=/remote-proctoring
|
|
||||||
sebserver.gui.remote.proctoring.api-servler.endpoint=/remote-view-servlet
|
|
||||||
|
|
||||||
# external libs / plugins
|
|
||||||
sebserver.gui.external.lib.aria.plugin.path=
|
|
||||||
|
|
||||||
# Webservice connection details
|
# Webservice connection details
|
||||||
sebserver.webservice.api.exam.endpoint=/exam-api
|
sebserver.webservice.api.exam.endpoint=/exam-api
|
||||||
sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery
|
sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery
|
||||||
|
|
|
@ -42,9 +42,9 @@ logging.level.ch=INFO
|
||||||
# logging.file=/sebserver/log/sebserver.log
|
# logging.file=/sebserver/log/sebserver.log
|
||||||
|
|
||||||
### spring actuator configuration
|
### spring actuator configuration
|
||||||
management.endpoints.jmx.exposure.include=metrics,logfile,loggers,heapdump,health
|
#management.endpoints.jmx.exposure.include=metrics,logfile,loggers,heapdump,health
|
||||||
management.endpoints.web.base-path=/mprofile
|
#management.endpoints.web.base-path=/mprofile
|
||||||
management.endpoints.web.exposure.include=metrics,logfile,loggers,heapdump,health
|
#management.endpoints.web.exposure.include=metrics,logfile,loggers,heapdump,health
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
### Overall Security Settings
|
### Overall Security Settings
|
||||||
|
@ -64,6 +64,7 @@ sebserver.ssl.redirect.enabled=false
|
||||||
sebserver.ssl.redirect.html.port=8080
|
sebserver.ssl.redirect.html.port=8080
|
||||||
|
|
||||||
# features
|
# features
|
||||||
|
sebserver.feature.setup.light.enabled=false
|
||||||
sebserver.feature.admin.institution.enabled=true
|
sebserver.feature.admin.institution.enabled=true
|
||||||
sebserver.feature.seb.remoteProctoring.enabled=true
|
sebserver.feature.seb.remoteProctoring.enabled=true
|
||||||
sebserver.feature.lms.testLMS.enabled=true
|
sebserver.feature.lms.testLMS.enabled=true
|
||||||
|
|
Loading…
Reference in a new issue