seb restriction switch, minor fixes for export

This commit is contained in:
anhefti 2019-11-05 09:15:28 +01:00
parent 2d016ed7fc
commit 78ffa7bc2c
18 changed files with 263 additions and 109 deletions

View file

@ -108,6 +108,7 @@ public final class API {
public static final String EXAM_ADMINISTRATION_ENDPOINT = "/exam";
public static final String EXAM_ADMINISTRATION_DOWNLOAD_CONFIG_PATH_SEGMENT = "/download-config";
public static final String EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT = "/check-consistency";
public static final String EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT = "/seb-restriction";
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";

View file

@ -67,6 +67,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SetExamSebRestriction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.ImportAsExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@ -308,7 +309,17 @@ public class ExamForm implements TemplateComposer {
.withEntityKey(entityKey)
.withAttribute(AttributeKeys.IMPORT_FROM_QUIZ_DATA, String.valueOf(importFromQuizData))
.withExec(this.cancelModifyFunction())
.publishIf(() -> !readonly);
.publishIf(() -> !readonly)
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
.withEntityKey(entityKey)
.withExec(action -> setSebRestriction(action, true))
.publishIf(() -> readonly && BooleanUtils.isFalse(exam.lmsSebRestriction))
.newAction(ActionDefinition.EXAM_DISABLE_SEB_RESTRICTION)
.withEntityKey(entityKey)
.withExec(action -> setSebRestriction(action, false))
.publishIf(() -> readonly && BooleanUtils.isTrue(exam.lmsSebRestriction));
// additional data in read-only view
if (readonly && !importFromQuizData) {
@ -491,6 +502,20 @@ public class ExamForm implements TemplateComposer {
message));
}
private PageAction setSebRestriction(final PageAction action, final boolean sebRestriction) {
this.restService.getBuilder(SetExamSebRestriction.class)
.withURIVariable(
API.PARAM_MODEL_ID,
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
.withQueryParam(
Domain.EXAM.ATTR_LMS_SEB_RESTRICTION,
sebRestriction ? Constants.TRUE_STRING : Constants.FALSE_STRING)
.call()
.onError(t -> action.pageContext().notifyError(t));
return action;
}
private PageAction viewExamConfigPageAction(final EntityTable<ExamConfigurationMap> table) {
return this.pageService.pageActionBuilder(table.getPageContext()

View file

@ -237,6 +237,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
urlLauncher.openURL(downloadURL);
return action;
})
.noEventPropagation()
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_GET_CONFIG_KEY)

View file

@ -226,6 +226,16 @@ public enum ActionDefinition {
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_ENABLE_SEB_RESTRICTION(
new LocTextKey("sebserver.exam.action.sebrestriction.enable"),
ImageIcon.TOGGLE_OFF,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_DISABLE_SEB_RESTRICTION(
new LocTextKey("sebserver.exam.action.deasebrestriction.disable"),
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.EXAM_VIEW,
ActionCategory.FORM),
EXAM_CONFIGURATION_NEW(
new LocTextKey("sebserver.exam.configuration.action.list.new"),

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class SetExamSebRestriction extends RestCall<Exam> {
public SetExamSebRestriction() {
super(new TypeKey<>(
CallType.SAVE,
EntityType.EXAM,
new TypeReference<Exam>() {
}),
HttpMethod.PATCH,
MediaType.APPLICATION_JSON_UTF8,
API.EXAM_ADMINISTRATION_ENDPOINT
+ API.MODEL_ID_VAR_PATH_SEGMENT
+ API.EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT);
}
}

View file

@ -54,4 +54,6 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
Result<Boolean> upToDate(Long examId, String lastUpdate);
Result<Exam> setSebRestriction(Long id, boolean sebRestriction);
}

View file

@ -190,6 +190,24 @@ public class ExamDAOImpl implements ExamDAO {
.onError(TransactionHandler::rollback);
}
@Override
@Transactional
public Result<Exam> setSebRestriction(final Long examId, final boolean sebRestriction) {
return Result.tryCatch(() -> {
final ExamRecord examRecord = new ExamRecord(
examId,
null, null, null, null, null, null, null, null, null,
BooleanUtils.toInteger(sebRestriction),
null, null, null);
this.examRecordMapper.updateByPrimaryKeySelective(examRecord);
return this.examRecordMapper.selectByPrimaryKey(examId);
})
.flatMap(this::toDomainModel)
.onError(TransactionHandler::rollback);
}
@Override
@Transactional
public Result<Exam> createNew(final Exam exam) {

View file

@ -8,43 +8,57 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SebRestrictionData;
@JsonIgnoreProperties(ignoreUnknown = true)
public class OpenEdxSebClientRestriction {
@JsonProperty("CONFIG_KEYS")
private static final String ATTR_USER_BANNING_ENABLED = "USER_BANNING_ENABLED";
private static final String ATTR_SEB_PERMISSION_COMPONENTS = "SEB_PERMISSION_COMPONENTS";
private static final String ATTR_BLACKLIST_CHAPTERS = "BLACKLIST_CHAPTERS";
private static final String ATTR_WHITELIST_PATHS = "WHITELIST_PATHS";
private static final String ATTR_BROWSER_KEYS = "BROWSER_KEYS";
private static final String ATTR_CONFIG_KEYS = "CONFIG_KEYS";
@JsonProperty(ATTR_CONFIG_KEYS)
public final Collection<String> configKeys;
@JsonProperty("BROWSER_KEYS")
@JsonProperty(ATTR_BROWSER_KEYS)
public final Collection<String> browserExamKeys;
@JsonProperty("WHITELIST_PATHS")
@JsonProperty(ATTR_WHITELIST_PATHS)
public final Collection<String> whiteListPaths;
@JsonProperty("BLACKLIST_CHAPTERS")
@JsonProperty(ATTR_BLACKLIST_CHAPTERS)
public final Collection<String> blacklistChapters;
@JsonProperty("SEB_PERMISSION_COMPONENTS")
@JsonProperty(ATTR_SEB_PERMISSION_COMPONENTS)
public final Collection<String> permissionComponents;
@JsonProperty("USER_BANNING_ENABLED")
@JsonProperty(ATTR_USER_BANNING_ENABLED)
public final boolean banningEnabled;
@JsonCreator
protected OpenEdxSebClientRestriction(
@JsonProperty("CONFIG_KEYS") final Collection<String> configKeys,
@JsonProperty("BROWSER_KEYS") final Collection<String> browserExamKeys,
@JsonProperty("WHITELIST_PATHS") final Collection<String> whiteListPaths,
@JsonProperty("BLACKLIST_CHAPTERS") final Collection<String> blacklistChapters,
@JsonProperty("SEB_PERMISSION_COMPONENTS") final Collection<String> permissionComponents,
@JsonProperty("USER_BANNING_ENABLED") final boolean banningEnabled) {
public OpenEdxSebClientRestriction(
@JsonProperty(ATTR_CONFIG_KEYS) final Collection<String> configKeys,
@JsonProperty(ATTR_BROWSER_KEYS) final Collection<String> browserExamKeys,
@JsonProperty(ATTR_WHITELIST_PATHS) final Collection<String> whiteListPaths,
@JsonProperty(ATTR_BLACKLIST_CHAPTERS) final Collection<String> blacklistChapters,
@JsonProperty(ATTR_SEB_PERMISSION_COMPONENTS) final Collection<String> permissionComponents,
@JsonProperty(ATTR_USER_BANNING_ENABLED) final boolean banningEnabled) {
this.configKeys = Utils.immutableCollectionOf(configKeys);
this.browserExamKeys = Utils.immutableCollectionOf(browserExamKeys);
@ -54,6 +68,37 @@ public class OpenEdxSebClientRestriction {
this.banningEnabled = banningEnabled;
}
public OpenEdxSebClientRestriction(final SebRestrictionData data) {
this.configKeys = Utils.immutableCollectionOf(data.configKeys);
this.browserExamKeys = Utils.immutableCollectionOf(data.browserExamKeys);
final String whiteListPaths = data.additionalAttributes.get(ATTR_WHITELIST_PATHS);
if (StringUtils.isNotBlank(whiteListPaths)) {
this.whiteListPaths = Utils.immutableCollectionOf(Arrays.asList(
StringUtils.split(whiteListPaths, Constants.LIST_SEPARATOR)));
} else {
this.whiteListPaths = Collections.emptyList();
}
final String blacklistChapters = data.additionalAttributes.get(ATTR_BLACKLIST_CHAPTERS);
if (StringUtils.isNotBlank(blacklistChapters)) {
this.blacklistChapters = Utils.immutableCollectionOf(Arrays.asList(
StringUtils.split(blacklistChapters, Constants.LIST_SEPARATOR)));
} else {
this.blacklistChapters = Collections.emptyList();
}
final String permissionComponents = data.additionalAttributes.get(ATTR_SEB_PERMISSION_COMPONENTS);
if (StringUtils.isNotBlank(permissionComponents)) {
this.permissionComponents = Utils.immutableCollectionOf(Arrays.asList(
StringUtils.split(permissionComponents, Constants.LIST_SEPARATOR)));
} else {
this.permissionComponents = Collections.emptyList();
}
this.banningEnabled = BooleanUtils.toBoolean(data.additionalAttributes.get(ATTR_USER_BANNING_ENABLED));
}
public Collection<String> getConfigKeys() {
return this.configKeys;
}

View file

@ -174,7 +174,7 @@ public class TableConverter implements AttributeValueConverter {
final ConfigurationAttribute attr = attrItr.next();
ConfigurationValue value = rowValues.stream()
.filter(val -> attr.id.equals(val.attributeId))
.filter(val -> val != null && attr.id.equals(val.attributeId))
.findFirst()
.orElse(null);

View file

@ -36,7 +36,7 @@ public interface ExamSessionService {
* @param examId the identifier of the Exam to check
* @return Result of one APIMessage per consistency check if the check failed. An empty Collection of everything is
* okay. */
Result<Collection<APIMessage>> checkRunningExamConsystency(Long examId);
Result<Collection<APIMessage>> checkRunningExamConsistency(Long examId);
/** Checks if a specified Exam has at least a default SEB Exam configuration attached.
*

View file

@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -130,38 +129,23 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
}
// generate the new Config Key and update the Config Key within the LMSSetup API for each exam (delete old Key and add new Key)
final Collection<Long> updatedExams = updateLmsSebRestriction(exams)
.stream()
.map(Result::get)
.filter(Objects::nonNull)
.map(Exam::getId)
.collect(Collectors.toList());
if (log.isDebugEnabled()) {
log.debug("Successfully updated ConfigKey for Exams: {}", updatedExams);
for (final Exam exam : exams) {
if (exam.getStatus() == ExamStatus.RUNNING) {
this.updateSebClientRestriction(exam)
.onError(t -> log.error("Failed to update SEB Client restriction for Exam: {}", exam, t));
}
}
// evict each Exam from cache and release the update-lock on DB
final Collection<Long> evictedExams = evictFromCache(exams)
.stream()
.filter(Result::hasValue)
.map(Result::get)
.map(Exam::getId)
.collect(Collectors.toList());
if (log.isDebugEnabled()) {
log.debug("Successfully evicted Exams from cache: {}", evictedExams);
for (final Exam exam : exams) {
this.examSessionService.flushCache(exam)
.onError(t -> log.error("Failed to flush Exam from cache: {}", exam, t));
}
// release the update-locks on involved exams
final Collection<Long> releasedLocks = releaseUpdateLocks(examIdsFirstCheck, updateId)
.stream()
.map(Result::getOrThrow)
.map(Exam::getId)
.collect(Collectors.toList());
if (log.isDebugEnabled()) {
log.debug("Successfully released update-locks on Exams: {}", releasedLocks);
for (final Long examId : examIdsFirstCheck) {
this.examDAO.releaseLock(examId, updateId)
.onError(t -> log.error("Failed to release lock for Exam: {}", examId, t));
}
return examIdsFirstCheck;
@ -296,43 +280,6 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
return this.examUpdateHandler.releaseSebClientRestriction(exam);
}
private void checkIntegrityDoubleCheck(
final Collection<Long> examIdsFirstCheck,
final Collection<Long> examIdsSecondCheck) {
if (examIdsFirstCheck.size() != examIdsSecondCheck.size()) {
throw new IllegalStateException("Running Exam integrity check missmatch. examIdsFirstCheck: "
+ examIdsFirstCheck + " examIdsSecondCheck: " + examIdsSecondCheck);
}
}
private Collection<Result<Exam>> lockForUpdate(final Collection<Long> examIds, final String update) {
return examIds.stream()
.map(id -> this.examDAO.placeLock(id, update))
.collect(Collectors.toList());
}
private Collection<Result<Exam>> releaseUpdateLocks(final Collection<Long> examIds, final String update) {
return examIds.stream()
.map(id -> this.examDAO.releaseLock(id, update))
.collect(Collectors.toList());
}
private Collection<Result<Exam>> updateLmsSebRestriction(final Collection<Exam> exams) {
return exams
.stream()
.filter(exam -> exam.getStatus() == ExamStatus.RUNNING)
.map(this::updateSebClientRestriction)
.collect(Collectors.toList());
}
private Collection<Result<Exam>> evictFromCache(final Collection<Exam> exams) {
return exams
.stream()
.map(this.examSessionService::flushCache)
.collect(Collectors.toList());
}
@Override
public Result<Collection<Long>> checkRunningExamIntegrity(final Long configurationNodeId) {
final Collection<Long> involvedExams = this.examConfigurationMapDAO
@ -397,4 +344,20 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
return false;
}
private void checkIntegrityDoubleCheck(
final Collection<Long> examIdsFirstCheck,
final Collection<Long> examIdsSecondCheck) {
if (examIdsFirstCheck.size() != examIdsSecondCheck.size()) {
throw new IllegalStateException("Running Exam integrity check missmatch. examIdsFirstCheck: "
+ examIdsFirstCheck + " examIdsSecondCheck: " + examIdsSecondCheck);
}
}
private Collection<Result<Exam>> lockForUpdate(final Collection<Long> examIds, final String update) {
return examIds.stream()
.map(id -> this.examDAO.placeLock(id, update))
.collect(Collectors.toList());
}
}

View file

@ -78,7 +78,7 @@ public class ExamSessionServiceImpl implements ExamSessionService {
}
@Override
public Result<Collection<APIMessage>> checkRunningExamConsystency(final Long examId) {
public Result<Collection<APIMessage>> checkRunningExamConsistency(final Long examId) {
return Result.tryCatch(() -> {
final Collection<APIMessage> result = new ArrayList<>();

View file

@ -120,10 +120,6 @@ class ExamUpdateHandler {
return Result.of(exam);
}
if (log.isDebugEnabled()) {
log.debug("Apply SEB Client restrictions for exam: {}", exam);
}
return Result.tryCatch(() -> {
final SebRestrictionData sebRestrictionData = createSebRestrictionData(exam);
@ -153,10 +149,6 @@ class ExamUpdateHandler {
final SebRestrictionData sebRestrictionData = createSebRestrictionData(exam);
if (log.isDebugEnabled()) {
log.debug("Update SEB Client restrictions for exam: {}", exam);
}
return this.lmsAPIService
.getLmsAPITemplate(exam.lmsSetupId)
.flatMap(lmsTemplate -> lmsTemplate.updateSebClientRestriction(sebRestrictionData))
@ -176,19 +168,6 @@ class ExamUpdateHandler {
.flatMap(template -> template.releaseSebClientRestriction(exam));
}
// @Transactional
// public <T> Result<T> updateExamConfigurationMappingChange(
// final ExamConfigurationMap mapping,
// final Function<ExamConfigurationMap, Result<T>> changeAction,
// final Exam exam) {
//
// return Result.tryCatch(() -> {
//
// return result;
// })
// .onError(TransactionHandler::rollback);
// }
private SebRestrictionData createSebRestrictionData(final Exam exam) {
final Collection<String> configKeys = this.sebExamConfigService
.generateConfigKeys(exam.institutionId, exam.id)
@ -206,7 +185,7 @@ class ExamUpdateHandler {
exam,
configKeys,
browserExamKeys,
// TODO when we have more restriction details available form the Exam, put it to the map
// TODO when we have more restriction details available from the Exam, put it to the map
Collections.emptyMap());
return sebRestrictionData;
}

View file

@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlTable;
import org.slf4j.Logger;
@ -60,6 +61,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
@ -75,6 +77,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
private final LmsAPIService lmsAPIService;
private final SebExamConfigService sebExamConfigService;
private final ExamSessionService examSessionService;
private final ExamConfigUpdateService examConfigUpdateService;
public ExamAdministrationController(
final AuthorizationService authorization,
@ -86,7 +89,8 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
final LmsAPIService lmsAPIService,
final UserDAO userDAO,
final SebExamConfigService sebExamConfigService,
final ExamSessionService examSessionService) {
final ExamSessionService examSessionService,
final ExamConfigUpdateService examConfigUpdateService) {
super(authorization,
bulkActionService,
@ -100,6 +104,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
this.lmsAPIService = lmsAPIService;
this.sebExamConfigService = sebExamConfigService;
this.examSessionService = examSessionService;
this.examConfigUpdateService = examConfigUpdateService;
}
@Override
@ -197,9 +202,39 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
+ API.EXAM_ADMINISTRATION_CONSISTENCY_CHECK_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Collection<APIMessage> checkExamConsistency(@PathVariable final Long modelId) {
public Collection<APIMessage> checkExamConsistency(
@PathVariable final Long modelId,
@RequestParam(
name = API.PARAM_INSTITUTION_ID,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
checkModifyPrivilege(institutionId);
return this.examSessionService
.checkRunningExamConsystency(modelId)
.checkRunningExamConsistency(modelId)
.getOrThrow();
}
@RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT
+ API.EXAM_ADMINISTRATION_SEB_RESTRICTION_PATH_SEGMENT,
method = RequestMethod.PATCH,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Exam switchSebRestriction(
@PathVariable final Long modelId,
@RequestParam(name = Domain.EXAM.ATTR_LMS_SEB_RESTRICTION, required = true) final boolean sebRestriction,
@RequestParam(
name = API.PARAM_INSTITUTION_ID,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
checkModifyPrivilege(institutionId);
return this.entityDAO.byPK(modelId)
.flatMap(this.authorization::checkModify)
.flatMap(this::checkNoActiveSebClientConnections)
.flatMap(exam -> this.setSebRestriction(exam, sebRestriction))
.flatMap(this.userActivityLogDAO::logModify)
.getOrThrow();
}
@ -291,4 +326,35 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
return exam;
}
private Result<Exam> checkNoActiveSebClientConnections(final Exam exam) {
if (this.examConfigUpdateService.hasActiveSebClientConnections(exam.id)) {
return Result.ofError(new APIMessageException(
APIMessage.ErrorMessage.INTEGRITY_VALIDATION
.of("Exam currently has active SEB Client connections.")));
}
return Result.of(exam);
}
private Result<Exam> setSebRestriction(final Exam exam, final boolean sebRestriction) {
return Result.tryCatch(() -> {
if (BooleanUtils.toBoolean(exam.lmsSebRestriction) == sebRestriction) {
return exam;
}
final Exam examUpdate = this.examDAO.setSebRestriction(exam.id, sebRestriction)
.getOrThrow();
if (sebRestriction) {
this.examConfigUpdateService.applySebClientRestriction(examUpdate)
.getOrThrow();
} else {
this.examConfigUpdateService.releaseSebClientRestriction(examUpdate)
.getOrThrow();
}
return examUpdate;
});
}
}

View file

@ -262,7 +262,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
(519, 'enableF11', 'CHECKBOX', null, null, null, null, 'false'),
(520, 'enableF12', 'CHECKBOX', null, null, null, null, 'false'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws:\\localhost:8706'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws://localhost:8706'),
(801, 'browserMessagingPingTime', 'INTEGER', null, null, null, null, '120000'),
(802, 'allowPreferencesWindow', 'CHECKBOX', null, null, null, null, 'true'),
(803, 'useAsymmetricOnlyEncryption', 'CHECKBOX', null, null, null, null, 'false'),

View file

@ -235,7 +235,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
(519, 'enableF11', 'CHECKBOX', null, null, null, null, 'false'),
(520, 'enableF12', 'CHECKBOX', null, null, null, null, 'false'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws:\\localhost:8706'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws://localhost:8706'),
(801, 'browserMessagingPingTime', 'INTEGER', null, null, null, null, '120000'),
(802, 'allowPreferencesWindow', 'CHECKBOX', null, null, null, null, 'true'),
(803, 'useAsymmetricOnlyEncryption', 'CHECKBOX', null, null, null, null, 'false'),

View file

@ -301,6 +301,8 @@ sebserver.exam.action.import=Import From Quizzes
sebserver.exam.action.save=Save Exam
sebserver.exam.action.activate=Activate Exam
sebserver.exam.action.deactivate=Deactivate Exam
sebserver.exam.action.sebrestriction.enable=Enable SEB Restriction
sebserver.exam.action.sebrestriction.disable=Disable SEB Restriction
sebserver.exam.info.pleaseSelect=Please Select an Exam first

View file

@ -243,7 +243,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
(519, 'enableF11', 'CHECKBOX', null, null, null, null, 'false'),
(520, 'enableF12', 'CHECKBOX', null, null, null, null, 'false'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws:\\localhost:8706'),
(800, 'browserMessagingSocket', 'TEXT_FIELD', null, null, null, null, 'ws://localhost:8706'),
(801, 'browserMessagingPingTime', 'INTEGER', null, null, null, null, '120000'),
(802, 'allowPreferencesWindow', 'CHECKBOX', null, null, null, null, 'true'),
(803, 'useAsymmetricOnlyEncryption', 'CHECKBOX', null, null, null, null, 'false'),