From bb0c834676a41955cfea44d407b9ffdb8f1c7150 Mon Sep 17 00:00:00 2001 From: anhefti Date: Mon, 24 Oct 2022 16:10:03 +0200 Subject: [PATCH] SEBSERV-351 implementation (no tests yet) --- .../dao/ConfigurationAttributeDAO.java | 6 ++ .../dao/ConfigurationValueDAO.java | 7 ++ .../impl/ConfigurationAttributeDAOImpl.java | 13 ++++ .../dao/impl/ConfigurationValueDAOImpl.java | 29 ++++++++ .../exam/ExamConfigurationValueService.java | 21 ++++++ .../ExamConfigurationValueServiceImpl.java | 69 +++++++++++++++++++ .../servicelayer/lms/SEBRestrictionAPI.java | 4 +- .../lms/impl/LmsAPITemplateAdapter.java | 6 +- .../lms/impl/SEBRestrictionServiceImpl.java | 2 +- .../lms/impl/ans/AnsLmsAPITemplate.java | 6 +- .../impl/edx/OpenEdxCourseRestriction.java | 8 +-- .../impl/mockup/MockSEBRestrictionAPI.java | 2 +- .../legacy/MoodleCourseRestriction.java | 4 +- .../plugin/MoodlePluginCourseRestriction.java | 4 +- .../lms/impl/olat/OlatLmsAPITemplate.java | 52 +++++++++++++- .../impl/olat/OlatLmsAPITemplateFactory.java | 5 ++ .../lms/impl/olat/OlatLmsData.java | 8 +++ 17 files changed, 226 insertions(+), 20 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamConfigurationValueService.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamConfigurationValueServiceImpl.java diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java index 698f6906..cf502c71 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationAttributeDAO.java @@ -28,4 +28,10 @@ public interface ConfigurationAttributeDAO extends EntityDAO> allChildAttributes(final Long parentId); + /** Use this to geht an attribute identifier by attribute name + * + * @param configAttributeName the attribute name + * @return Result refer to the attribute identifier or to an error if happened */ + Result getAttributeIdByName(String configAttributeName); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationValueDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationValueDAO.java index a56d0da4..3fce151f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationValueDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationValueDAO.java @@ -71,4 +71,11 @@ public interface ConfigurationValueDAO extends EntityDAO getConfigAttributeValue(Long configId, Long attrId); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java index a7a6964e..907379da 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationAttributeDAOImpl.java @@ -93,6 +93,19 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO }); } + @Override + @Transactional(readOnly = true) + public Result getAttributeIdByName(final String attributeName) { + return Result.tryCatch(() -> this.configurationAttributeRecordMapper + .selectByExample() + .where( + ConfigurationAttributeRecordDynamicSqlSupport.name, + SqlBuilder.isEqualTo(attributeName)) + .build() + .execute() + .get(0).getId()); + } + @Override @Transactional(readOnly = true) public Result> allMatching( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationValueDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationValueDAOImpl.java index 1bfbcc7c..42c08c56 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationValueDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationValueDAOImpl.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -122,6 +123,34 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO { .collect(Collectors.toList())); } + @Override + public Result getConfigAttributeValue(final Long configId, final Long attrId) { + return Result.tryCatch(() -> { + + final List records = this.configurationValueRecordMapper.selectByExample() + .where( + ConfigurationValueRecordDynamicSqlSupport.configurationId, + isEqualTo(configId)) + + .and( + ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId, + SqlBuilder.isEqualTo(attrId)) + .build() + .execute(); + + if (records == null) { + throw new NoSuchElementException( + "No SEB setting attribute value found for configId: " + configId + " attrId: " + attrId); + } + if (records.size() > 1) { + log.warn("Found more then one attribute value for configId: {}, attrId:{} select first one.", configId, + attrId); + } + + return records.get(0).getValue(); + }); + } + @Override @Transactional(readOnly = true) public Result> allOf(final Set pks) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamConfigurationValueService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamConfigurationValueService.java new file mode 100644 index 00000000..a46fb07c --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamConfigurationValueService.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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.webservice.servicelayer.exam; + +public interface ExamConfigurationValueService { + + /** Get the actual SEB settings attribute value for the exam configuration mapped as default configuration + * to the given exam + * + * @param examId The exam identifier + * @param configAttributeName The name of the SEB settings attribute + * @return The current value of the above SEB settings attribute and given exam. */ + String getMappedDefaultConfigAttributeValue(Long examId, String configAttributeName); + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamConfigurationValueServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamConfigurationValueServiceImpl.java new file mode 100644 index 00000000..f666b0d7 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamConfigurationValueServiceImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 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.webservice.servicelayer.exam.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationValueDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService; + +@Service +public class ExamConfigurationValueServiceImpl implements ExamConfigurationValueService { + + private static final Logger log = LoggerFactory.getLogger(ExamConfigurationValueServiceImpl.class); + + private final ExamConfigurationMapDAO examConfigurationMapDAO; + private final ConfigurationDAO configurationDAO; + private final ConfigurationAttributeDAO configurationAttributeDAO; + private final ConfigurationValueDAO configurationValueDAO; + + public ExamConfigurationValueServiceImpl( + final ExamConfigurationMapDAO examConfigurationMapDAO, + final ConfigurationDAO configurationDAO, + final ConfigurationAttributeDAO configurationAttributeDAO, + final ConfigurationValueDAO configurationValueDAO) { + + this.examConfigurationMapDAO = examConfigurationMapDAO; + this.configurationDAO = configurationDAO; + this.configurationAttributeDAO = configurationAttributeDAO; + this.configurationValueDAO = configurationValueDAO; + } + + @Override + public String getMappedDefaultConfigAttributeValue(final Long examId, final String configAttributeName) { + try { + + final Long configId = this.examConfigurationMapDAO + .getDefaultConfigurationNode(examId) + .flatMap(nodeId -> this.configurationDAO.getConfigurationLastStableVersion(nodeId)) + .map(config -> config.id) + .getOrThrow(); + + final Long attrId = this.configurationAttributeDAO + .getAttributeIdByName(configAttributeName) + .onError(error -> log.error("Failed to get attribute id with name: {} for exam: {}", + configAttributeName, examId, error)) + .getOr(null); + + return this.configurationValueDAO + .getConfigAttributeValue(configId, attrId) + .getOrThrow(); + + } catch (final Exception e) { + log.error("Unexpected error while trying to extract SEB settings attribute value:", e); + return null; + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/SEBRestrictionAPI.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/SEBRestrictionAPI.java index 679d7faa..c7a001df 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/SEBRestrictionAPI.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/SEBRestrictionAPI.java @@ -56,12 +56,12 @@ public interface SEBRestrictionAPI { /** Applies SEB Client restrictions to the LMS with the given attributes. * - * @param externalExamId The exam/course identifier from LMS side (Exam.externalId) + * @param exam The exam to apply the restriction for * @param sebRestrictionData containing all data for SEB Client restriction to apply to the LMS * @return Result refer to the given {@link SEBRestrictionData } if restriction was successful or to an error if * not */ Result applySEBClientRestriction( - String externalExamId, + Exam exam, SEBRestriction sebRestrictionData); /** Releases an already applied SEB Client restriction within the LMS for a given Exam. diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java index e613beb3..888ad639 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java @@ -409,7 +409,7 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate { @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { if (this.sebRestrictionAPI == null) { @@ -418,11 +418,11 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate { } if (log.isDebugEnabled()) { - log.debug("Apply course restriction: {} for LMSSetup: {}", externalExamId, lmsSetup()); + log.debug("Apply course restriction: {} for LMSSetup: {}", exam, lmsSetup()); } return this.restrictionRequest.protectedRun(() -> this.sebRestrictionAPI - .applySEBClientRestriction(externalExamId, sebRestrictionData) + .applySEBClientRestriction(exam, sebRestrictionData) .onError(error -> log.error( "Failed to apply SEB restrictions: {}", error.getMessage())) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/SEBRestrictionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/SEBRestrictionServiceImpl.java index 417d6899..677de63c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/SEBRestrictionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/SEBRestrictionServiceImpl.java @@ -237,7 +237,7 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService { return this.lmsAPIService .getLmsAPITemplate(exam.lmsSetupId) .flatMap(lmsTemplate -> lmsTemplate.applySEBClientRestriction( - exam.externalId, + exam, sebRestrictionData)) .map(data -> exam) .getOrThrow(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java index 36a51636..3cca3c40 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java @@ -56,8 +56,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.AbstractCachedCourseAccess; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.ans.AnsLmsData.SEBServerData; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.ans.AnsLmsData.AssignmentData; +import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.ans.AnsLmsData.SEBServerData; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.ans.AnsLmsData.UserData; public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements LmsAPITemplate { @@ -371,10 +371,10 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { return getRestTemplate() - .map(t -> this.setRestrictionForAssignmentId(t, externalExamId, sebRestrictionData)); + .map(t -> this.setRestrictionForAssignmentId(t, exam.externalId, sebRestrictionData)); } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseRestriction.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseRestriction.java index 23b91b85..9de46588 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseRestriction.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseRestriction.java @@ -148,16 +148,16 @@ public class OpenEdxCourseRestriction implements SEBRestrictionAPI { @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { if (log.isDebugEnabled()) { - log.debug("PUT SEB Client restriction on course: {} : {}", externalExamId, sebRestrictionData); + log.debug("PUT SEB Client restriction on course: {} : {}", exam.externalId, sebRestrictionData); } return Result.tryCatch(() -> { final LmsSetup lmsSetup = this.openEdxRestTemplateFactory.apiTemplateDataSupplier.getLmsSetup(); - final String url = lmsSetup.lmsApiUrl + getSEBRestrictionUrl(externalExamId); + final String url = lmsSetup.lmsApiUrl + getSEBRestrictionUrl(exam.externalId); final HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); httpHeaders.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); @@ -172,7 +172,7 @@ public class OpenEdxCourseRestriction implements SEBRestrictionAPI { .getBody(); if (log.isDebugEnabled()) { - log.debug("Successfully PUT SEB Client restriction on course: {} : {}", externalExamId, body); + log.debug("Successfully PUT SEB Client restriction on course: {} : {}", exam.externalId, body); } return sebRestrictionData; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockSEBRestrictionAPI.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockSEBRestrictionAPI.java index 5cfe2360..a2443385 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockSEBRestrictionAPI.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockSEBRestrictionAPI.java @@ -36,7 +36,7 @@ public class MockSEBRestrictionAPI implements SEBRestrictionAPI { @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { log.info("Apply SEB Client restriction: {}", sebRestrictionData); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseRestriction.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseRestriction.java index ccff2e87..96008d34 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseRestriction.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseRestriction.java @@ -126,11 +126,11 @@ public class MoodleCourseRestriction implements SEBRestrictionAPI { @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { return this.updateSEBRestriction( - externalExamId, + exam.externalId, MoodleSEBRestriction.from(sebRestrictionData)) .map(result -> sebRestrictionData); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseRestriction.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseRestriction.java index d2eeb5e3..162e631f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseRestriction.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseRestriction.java @@ -29,8 +29,10 @@ public class MoodlePluginCourseRestriction implements SEBRestrictionAPI { } @Override - public Result applySEBClientRestriction(final String externalExamId, + public Result applySEBClientRestriction( + final Exam exam, final SEBRestriction sebRestrictionData) { + // TODO Auto-generated method stub return null; } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java index 6b27ca98..81d2d39a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java @@ -49,6 +49,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; +import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; @@ -62,9 +63,16 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm private static final Logger log = LoggerFactory.getLogger(OlatLmsAPITemplate.class); + private static final String ADDITIONAL_ATTR_QUIT_LINK = "ADDITIONAL_ATTR_QUIT_LINK"; + private static final String ADDITIONAL_ATTR_QUIT_SECRET = "ADDITIONAL_ATTR_QUIT_SECRET"; + + private static final String CONFIG_ATTR_NAME_QUIT_LINK = "quitURL"; + private static final String CONFIG_ATTR_NAME_QUIT_SECRET = "hashedQuitPassword"; + private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; private final ClientCredentialService clientCredentialService; private final APITemplateDataSupplier apiTemplateDataSupplier; + private final ExamConfigurationValueService examConfigurationValueService; private final Long lmsSetupId; private OlatLmsRestTemplate cachedRestTemplate; @@ -73,6 +81,7 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm final ClientHttpRequestFactoryService clientHttpRequestFactoryService, final ClientCredentialService clientCredentialService, final APITemplateDataSupplier apiTemplateDataSupplier, + final ExamConfigurationValueService examConfigurationValueService, final CacheManager cacheManager) { super(cacheManager); @@ -80,6 +89,7 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; this.clientCredentialService = clientCredentialService; this.apiTemplateDataSupplier = apiTemplateDataSupplier; + this.examConfigurationValueService = examConfigurationValueService; this.lmsSetupId = apiTemplateDataSupplier.getLmsSetup().id; } @@ -310,7 +320,15 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm private SEBRestriction getRestrictionForAssignmentId(final RestTemplate restTemplate, final String id) { final String url = String.format("/restapi/assessment_modes/%s/seb_restriction", id); final RestrictionData r = this.apiGet(restTemplate, url, RestrictionData.class); - return new SEBRestriction(Long.valueOf(id), r.configKeys, r.browserExamKeys, new HashMap()); + final HashMap additionalAttributes = new HashMap<>(); + if (StringUtils.isNotBlank(r.quitLink)) { + additionalAttributes.put(ADDITIONAL_ATTR_QUIT_LINK, r.quitLink); + } + if (StringUtils.isNotBlank(r.quitSecret)) { + additionalAttributes.put(ADDITIONAL_ATTR_QUIT_SECRET, r.quitSecret); + } + + return new SEBRestriction(Long.valueOf(id), r.configKeys, r.browserExamKeys, additionalAttributes); } private SEBRestriction setRestrictionForAssignmentId( @@ -322,6 +340,8 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm final RestrictionDataPost post = new RestrictionDataPost(); post.browserExamKeys = new ArrayList<>(restriction.browserExamKeys); post.configKeys = new ArrayList<>(restriction.configKeys); + post.quitLink = restriction.getAdditionalProperties().getOrDefault(ADDITIONAL_ATTR_QUIT_LINK, null); + post.quitSecret = restriction.getAdditionalProperties().getOrDefault(ADDITIONAL_ATTR_QUIT_SECRET, null); final RestrictionData r = this.apiPost(restTemplate, url, post, RestrictionDataPost.class, RestrictionData.class); return new SEBRestriction(Long.valueOf(id), r.configKeys, r.browserExamKeys, new HashMap()); @@ -343,10 +363,12 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm @Override public Result applySEBClientRestriction( - final String externalExamId, + final Exam exam, final SEBRestriction sebRestrictionData) { + + populateWithQuitLinkAndSecret(exam, sebRestrictionData); return getRestTemplate() - .map(t -> this.setRestrictionForAssignmentId(t, externalExamId, sebRestrictionData)); + .map(t -> this.setRestrictionForAssignmentId(t, exam.externalId, sebRestrictionData)); } @Override @@ -433,4 +455,28 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm }); } + private void populateWithQuitLinkAndSecret(final Exam exam, final SEBRestriction sebRestrictionData) { + try { + + final String quitLink = this.examConfigurationValueService.getMappedDefaultConfigAttributeValue( + exam.id, + CONFIG_ATTR_NAME_QUIT_LINK); + + final String quitSecret = this.examConfigurationValueService.getMappedDefaultConfigAttributeValue( + exam.id, + CONFIG_ATTR_NAME_QUIT_SECRET); + + if (StringUtils.isNotEmpty(quitLink)) { + sebRestrictionData.additionalProperties.put(ADDITIONAL_ATTR_QUIT_LINK, quitLink); + } + + if (StringUtils.isNotEmpty(quitSecret)) { + sebRestrictionData.additionalProperties.put(ADDITIONAL_ATTR_QUIT_SECRET, quitSecret); + } + + } catch (final Exception e) { + log.error("Failed to populate SEB restriction with quit link and quit secret: ", e); + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplateFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplateFactory.java index 3330737b..6810ae33 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplateFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplateFactory.java @@ -19,6 +19,7 @@ import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory; @@ -38,6 +39,7 @@ public class OlatLmsAPITemplateFactory implements LmsAPITemplateFactory { private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; private final ClientCredentialService clientCredentialService; + private final ExamConfigurationValueService examConfigurationValueService; private final AsyncService asyncService; private final Environment environment; private final CacheManager cacheManager; @@ -45,12 +47,14 @@ public class OlatLmsAPITemplateFactory implements LmsAPITemplateFactory { public OlatLmsAPITemplateFactory( final ClientHttpRequestFactoryService clientHttpRequestFactoryService, final ClientCredentialService clientCredentialService, + final ExamConfigurationValueService examConfigurationValueService, final AsyncService asyncService, final Environment environment, final CacheManager cacheManager) { this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; this.clientCredentialService = clientCredentialService; + this.examConfigurationValueService = examConfigurationValueService; this.asyncService = asyncService; this.environment = environment; this.cacheManager = cacheManager; @@ -68,6 +72,7 @@ public class OlatLmsAPITemplateFactory implements LmsAPITemplateFactory { this.clientHttpRequestFactoryService, this.clientCredentialService, apiTemplateDataSupplier, + this.examConfigurationValueService, this.cacheManager); return new LmsAPITemplateAdapter( this.asyncService, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsData.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsData.java index 7aab3e28..d075b0c9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsData.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsData.java @@ -61,12 +61,16 @@ public final class OlatLmsData { * { * "browserExamKeys": [ "1" ], * "configKeys": null, + * "quitLink": "", + * "quitSecret": "", * "key": 8028160 * } */ public long key; public List browserExamKeys; public List configKeys; + public String quitLink; + public String quitSecret; } @JsonIgnoreProperties(ignoreUnknown = true) @@ -76,10 +80,14 @@ public final class OlatLmsData { * { * "configKeys": ["a", "b"], * "browserExamKeys": ["1", "2"] + * "quitLink": "", + * "quitSecret": "", * } */ public List browserExamKeys; public List configKeys; + public String quitLink; + public String quitSecret; } }