From 16b2c8deb44b7fb7e21adbdfb386938cc94f1d3c Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 3 Jul 2024 16:29:00 +0200 Subject: [PATCH] SEBSERV-559 and SEBSERV-552 --- .../MonitoringProctoringService.java | 6 ++- .../authorization/AdHocAccountData.java | 34 +++++++++++++ .../authorization/TeacherAccountService.java | 6 +-- .../authorization/UserService.java | 2 + .../impl/TeacherAccountServiceImpl.java | 17 +++---- .../exam/impl/ExamTemplateServiceImpl.java | 3 +- .../lms/FullLmsIntegrationService.java | 27 +---------- .../impl/FullLmsIntegrationServiceImpl.java | 23 ++++++--- .../session/ScreenProctoringService.java | 3 ++ .../ScreenProctoringAPIBinding.java | 48 ++++++++++--------- .../ScreenProctoringServiceImpl.java | 30 ++++++++---- .../api/LmsIntegrationController.java | 22 ++++++--- 12 files changed, 131 insertions(+), 90 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AdHocAccountData.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java index 900a09f1..22fa09d2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java @@ -169,7 +169,6 @@ public class MonitoringProctoringService { final ScreenProctoringSettings screenProctoringSettings) { collectingRooms - .stream() .forEach(room -> updateProctoringAction( pageContext, proctoringSettings, @@ -184,7 +183,6 @@ public class MonitoringProctoringService { if (screenProctoringGroups != null) { screenProctoringGroups - .stream() .forEach(group -> updateScreenProctoringAction( pageContext, screenProctoringSettings, @@ -357,8 +355,12 @@ public class MonitoringProctoringService { // Open SPS Gui redirect URL with login token (jwt token) in new browser tab final String redirectLocation = redirect.getBody() + "/jwt?token=" + tokenRequest.getBody(); + final String script = "window.open("+ redirectLocation + ", 'seb_screen_proctoring')"; final UrlLauncher launcher = RWT.getClient().getService(UrlLauncher.class); launcher.openURL(redirectLocation); +// RWT.getClient() +// .getService(JavaScriptExecutor.class) +// .execute(script); } catch (final Exception e) { log.error("Failed to open screen proctoring service group gallery view: ", e); _action.pageContext() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AdHocAccountData.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AdHocAccountData.java new file mode 100644 index 00000000..e2ea6f7f --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AdHocAccountData.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 ETH Zürich, IT Services + * + * 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.authorization; + +public final class AdHocAccountData { + public final String userId; + public final String username; + public final String userMail; + public final String firstName; + public final String lastName; + public final String timezone; + + public AdHocAccountData( + final String userId, + final String username, + final String userMail, + final String firstName, + final String lastName, + final String timezone) { + + this.userId = userId; + this.username = username; + this.userMail = userMail; + this.firstName = firstName; + this.lastName = lastName; + this.timezone = timezone; + } +} \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/TeacherAccountService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/TeacherAccountService.java index e5e18723..a41c76d1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/TeacherAccountService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/TeacherAccountService.java @@ -27,7 +27,7 @@ public interface TeacherAccountService { */ Result createNewTeacherAccountForExam( Exam exam, - final FullLmsIntegrationService.AdHocAccountData adHocAccountData); + final AdHocAccountData adHocAccountData); /** Get the identifier for certain Teacher account for specified Exam. * @@ -37,7 +37,7 @@ public interface TeacherAccountService { */ default String getTeacherAccountIdentifier( final Exam exam, - final FullLmsIntegrationService.AdHocAccountData adHocAccountData) { + final AdHocAccountData adHocAccountData) { return getTeacherAccountIdentifier( String.valueOf(exam.lmsSetupId), @@ -62,7 +62,7 @@ public interface TeacherAccountService { */ Result getOneTimeTokenForTeacherAccount( Exam exam, - FullLmsIntegrationService.AdHocAccountData adHocAccountData, + AdHocAccountData adHocAccountData, boolean createIfNotExists); /** Used to verify a given One Time Access JWT Token. This must have the expected claims and must not be expired diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/UserService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/UserService.java index fde10800..48762227 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/UserService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/UserService.java @@ -20,6 +20,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServe public interface UserService { String USERS_INSTITUTION_AS_DEFAULT = "USERS_INSTITUTION_AS_DEFAULT"; + + /** UUID of the internal account that is used for LMS integration related remote call tasks */ String LMS_INTEGRATION_CLIENT_UUID = "LMS_INTEGRATION_CLIENT"; String LMS_INTEGRATION_CLIENT_NAME = "lmsIntegrationClient"; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/TeacherAccountServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/TeacherAccountServiceImpl.java index 38e8e803..4cf6c925 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/TeacherAccountServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/TeacherAccountServiceImpl.java @@ -20,10 +20,10 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AdHocAccountData; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.TeacherAccountService; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService; import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService; import ch.ethz.seb.sebserver.webservice.weblayer.oauth.AdminAPIClientDetails; import io.jsonwebtoken.Claims; @@ -91,7 +91,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { @Override public Result createNewTeacherAccountForExam( final Exam exam, - final FullLmsIntegrationService.AdHocAccountData adHocAccountData) { + final AdHocAccountData adHocAccountData) { return Result.tryCatch(() -> { @@ -130,7 +130,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { @Override public Result getOneTimeTokenForTeacherAccount( final Exam exam, - final FullLmsIntegrationService.AdHocAccountData adHocAccountData, + final AdHocAccountData adHocAccountData, final boolean createIfNotExists) { return this.userDAO @@ -186,7 +186,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { private UserInfo handleAccountDoesNotExistYet( final boolean createIfNotExists, final Exam exam, - final FullLmsIntegrationService.AdHocAccountData adHocAccountData) { + final AdHocAccountData adHocAccountData) { if (createIfNotExists) { return this @@ -212,6 +212,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { "Failed to apply ad-hoc-teacher account to supporter list of exam: {} user: {}", exam, account, error)); } + return account; } @@ -219,7 +220,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { final String subjectClaim = UUID.randomUUID().toString(); userDAO.changePassword(account.uuid, subjectClaim); - synchronizeSPSUserForExam(account, examId); + this.screenProctoringService.updateExamOnScreenProctoringService(examId); final Map claims = new HashMap<>(); claims.put(USER_CLAIM, account.uuid); @@ -275,10 +276,4 @@ public class TeacherAccountServiceImpl implements TeacherAccountService { return claims; } - private UserInfo synchronizeSPSUserForExam(final UserInfo account, final Long examId) { - if (this.screenProctoringService.isScreenProctoringEnabled(examId)) { - this.screenProctoringService.synchronizeSPSUserForExam(examId); - } - return account; - } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamTemplateServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamTemplateServiceImpl.java index cb2aa143..70ad5b4b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamTemplateServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamTemplateServiceImpl.java @@ -16,7 +16,6 @@ import java.util.Objects; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.*; import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ProctoringAdminService; -import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; @@ -299,7 +298,7 @@ public class ExamTemplateServiceImpl implements ExamTemplateService { !Objects.equals(examConfig.templateId, examTemplate.configTemplateId)) { final String newName = (examConfig != null && examConfig.name.equals(configName)) - ? examConfig.name + "_" + ? examConfig.name + "_" + DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_FORMATTER) : configName; final ConfigurationNode config = new ConfigurationNode( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/FullLmsIntegrationService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/FullLmsIntegrationService.java index 6d437209..637d9f9c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/FullLmsIntegrationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/FullLmsIntegrationService.java @@ -11,12 +11,11 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms; import java.io.OutputStream; import java.util.Collection; -import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; -import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AdHocAccountData; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent; import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamTemplateChangeEvent; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent; @@ -26,7 +25,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.context.event.EventListener; -import org.springframework.web.bind.annotation.RequestParam; public interface FullLmsIntegrationService { @@ -79,30 +77,7 @@ public interface FullLmsIntegrationService { AdHocAccountData adHocAccountData); - final class AdHocAccountData { - public final String userId; - public final String username; - public final String userMail; - public final String firstName; - public final String lastName; - public final String timezone; - public AdHocAccountData( - final String userId, - final String username, - final String userMail, - final String firstName, - final String lastName, - final String timezone) { - - this.userId = userId; - this.username = username; - this.userMail = userMail; - this.firstName = firstName; - this.lastName = lastName; - this.timezone = timezone; - } - } @JsonIgnoreProperties(ignoreUnknown = true) final class ExamData { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/FullLmsIntegrationServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/FullLmsIntegrationServiceImpl.java index d2b0a1b0..b6244a3d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/FullLmsIntegrationServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/FullLmsIntegrationServiceImpl.java @@ -32,6 +32,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AdHocAccountData; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.TeacherAccountServiceImpl; @@ -455,14 +456,22 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService final String quizId, final String examData) { - final String internalQuizId = MoodleUtils.getInternalQuizId( - quizId, - courseId, - null, - null); + if (StringUtils.isNotBlank(examData)) { + return lmsAPITemplate + .getQuizDataForRemoteImport(examData) + .getOrThrow(); + } else { - return lmsAPITemplate.getQuizDataForRemoteImport(examData) - .getOrThrow(); + final String internalQuizId = MoodleUtils.getInternalQuizId( + quizId, + courseId, + null, + null); + + return lmsAPITemplate.getQuiz(internalQuizId) + .getOrThrow(); + + } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ScreenProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ScreenProctoringService.java index 5cc3b049..36c0a309 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ScreenProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ScreenProctoringService.java @@ -71,6 +71,9 @@ public interface ScreenProctoringService extends SessionUpdateTask { @EventListener(ExamFinishedEvent.class) void notifyExamFinished(ExamFinishedEvent event); + @EventListener(ExamResetEvent.class) + void notifyExamReset(ExamResetEvent event); + /** This is being called just before an Exam gets deleted on the permanent storage. * This deactivates and dispose or deletes all exam relevant domain entities on the SPS service side. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java index 957e9e89..4d204b6c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java @@ -102,6 +102,12 @@ class ScreenProctoringAPIBinding { String ATTR_PRIVILEGES = "privileges"; } + interface PRIVILEGE_FLAGS { + String READ = "r"; + String MODIFY = "m"; + String WRITE = "w"; + } + /** The screen proctoring service client-access API attribute names */ interface SEB_ACCESS { String ATTR_UUID = "uuid"; @@ -380,8 +386,6 @@ class ScreenProctoringAPIBinding { void synchronizeUserAccounts(final Exam exam) { try { - final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id); - final SPSData spsData = this.getSPSData(exam.id); exam.supporter.forEach(userUUID -> synchronizeUserAccount(userUUID, apiTemplate)); if (exam.owner != null) { @@ -389,7 +393,7 @@ class ScreenProctoringAPIBinding { } } catch (final Exception e) { - log.error("Failed to synchronize user accounts with SPS for exam: {}", exam); + log.error("Failed to synchronize user accounts with SPS for exam: {}", exam, e); } } void deleteSPSUser(final String userUUID) { @@ -433,11 +437,7 @@ class ScreenProctoringAPIBinding { .build() .toUriString(); - final List userIds = new ArrayList<>(exam.supporter); - if (exam.owner != null) { - userIds.add(exam.owner); - } - + final List supporterIds = getSupporterIds(exam); final ExamUpdate examUpdate = new ExamUpdate( exam.name, exam.getDescription(), @@ -445,7 +445,7 @@ class ScreenProctoringAPIBinding { exam.getType().name(), exam.startTime != null ? exam.startTime.getMillis() : null, exam.endTime != null ? exam.endTime.getMillis() : null, - userIds); + supporterIds); final String jsonExamUpdate = this.jsonMapper.writeValueAsString(examUpdate); @@ -796,17 +796,15 @@ class ScreenProctoringAPIBinding { if (activityRequest.getStatusCode() != HttpStatus.OK) { final String body = activityRequest.getBody(); - if (body != null && body.contains("Activation argument mismatch")) { - return; + if (body != null && !body.contains("Activation argument mismatch")) { + log.warn("Failed to synchronize activity for user account on SPS: {}", activityRequest); } - - log.warn("Failed to synchronize activity for user account on SPS: {}", activityRequest); } else { log.info("Successfully synchronize activity for user account on SPS for user: {}", userUUID); } } catch (final Exception e) { - log.error("Failed to synchronize user account with SPS for user: {}", userUUID); + log.error("Failed to synchronize user account with SPS for user: {}", userUUID, e); } } @@ -931,18 +929,14 @@ class ScreenProctoringAPIBinding { try { - final List userIds = new ArrayList<>(exam.supporter); - if (exam.owner != null) { - userIds.add(exam.owner); - } - + final List supporterIds = getSupporterIds(exam); final String uri = UriComponentsBuilder .fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL()) .path(SPS_API.EXAM_ENDPOINT) .build().toUriString(); final String uuid = createExamUUID(exam); - final MultiValueMap params = createExamCreationParams(exam, uuid, userIds); + final MultiValueMap params = createExamCreationParams(exam, uuid, supporterIds); final String paramsFormEncoded = Utils.toAppFormUrlEncodedBodyForSPService(params); final ResponseEntity exchange = apiTemplate.exchange(uri, paramsFormEncoded); @@ -976,7 +970,7 @@ class ScreenProctoringAPIBinding { private static MultiValueMap createExamCreationParams( final Exam exam, final String uuid, - final List userIds) { + final List supporterIds) { final MultiValueMap params = new LinkedMultiValueMap<>(); params.add(SPS_API.EXAM.ATTR_UUID, uuid); @@ -985,8 +979,8 @@ class ScreenProctoringAPIBinding { params.add(SPS_API.EXAM.ATTR_DESCRIPTION, exam.getDescription()); } params.add(SPS_API.EXAM.ATTR_URL, exam.getStartURL()); - if (!userIds.isEmpty()) { - params.add(SPS_API.EXAM.ATTR_USER_IDS, StringUtils.join(userIds, Constants.LIST_SEPARATOR)); + if (!supporterIds.isEmpty()) { + params.add(SPS_API.EXAM.ATTR_USER_IDS, StringUtils.join(supporterIds, Constants.LIST_SEPARATOR)); } params.add(SPS_API.EXAM.ATTR_TYPE, exam.getType().name()); params.add(SPS_API.EXAM.ATTR_START_TIME, String.valueOf(exam.startTime.getMillis())); @@ -1199,6 +1193,14 @@ class ScreenProctoringAPIBinding { return this.apiTemplate; } + private static List getSupporterIds(final Exam exam) { + final List supporterIds = new ArrayList<>(exam.supporter); + if (exam.owner != null && !UserService.LMS_INTEGRATION_CLIENT_UUID.equals(exam.owner)) { + supporterIds.add(exam.owner); + } + return supporterIds; + } + final static class ScreenProctoringServiceOAuthTemplate { private static final String GRANT_TYPE = "password"; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java index 559eddcf..daab9ebd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java @@ -17,6 +17,7 @@ import ch.ethz.seb.sebserver.gbl.model.Activatable; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent; +import ch.ethz.seb.sebserver.webservice.servicelayer.session.*; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -47,10 +48,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ScreenProctoringGroupDA import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ScreenProctoringGroupDAOImpl.AllGroupsFullException; -import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamFinishedEvent; -import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamStartedEvent; -import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService; -import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService; import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ExamSessionCacheService; import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring.ScreenProctoringAPIBinding.SPSData; @@ -270,7 +267,8 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService { @Override public void synchronizeSPSUserForExam(final Long examId) { - this.examDAO.byPK(examId) + this.examDAO + .byPK(examId) .onSuccess(this.screenProctoringAPIBinding::synchronizeUserAccounts) .onError(error -> log.error("Failed to synchronize SPS user accounts for exam: {}", examId, error)); } @@ -299,14 +297,26 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService { @Override public void notifyExamFinished(final ExamFinishedEvent event) { - final Exam exam = event.exam; - if (!this.isScreenProctoringEnabled(exam.id) || - !BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) { + + if (!this.isScreenProctoringEnabled(event.exam.id) || + !BooleanUtils.toBoolean(event.exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) { return; } - if (exam.status == Exam.ExamStatus.FINISHED) { - this.screenProctoringAPIBinding.deactivateScreenProctoring(exam); + if (event.exam.status != Exam.ExamStatus.UP_COMING) { + this.screenProctoringAPIBinding.deactivateScreenProctoring(event.exam); + } + } + + @Override + public void notifyExamReset(final ExamResetEvent event) { + if (!this.isScreenProctoringEnabled(event.exam.id) || + BooleanUtils.toBoolean(event.exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) { + return; + } + + if (event.exam.status != Exam.ExamStatus.UP_COMING) { + this.screenProctoringAPIBinding.activateScreenProctoring(event.exam); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsIntegrationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsIntegrationController.java index 2b139138..9124be8e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsIntegrationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsIntegrationController.java @@ -21,6 +21,8 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AdHocAccountData; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.NoResourceFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.BooleanUtils; @@ -89,15 +91,23 @@ public class LmsIntegrationController { examData) .onError(e -> { log.error( - "Failed to create/import exam: lmsId:{}, courseId: {}, quizId: {}, templateId: {} error: {}", - lmsUUId, courseId, quizId, templateId, e.getMessage()); + "Failed to create/import exam: lmsId:{}, courseId: {}, quizId: {}, templateId: {} error: ", + lmsUUId, courseId, quizId, templateId, e); log.info("Rollback Exam creation..."); fullLmsIntegrationService.deleteExam(lmsUUId, courseId, quizId) - .onError(error -> log.error("Failed to rollback auto Exam import: ", error)); + .onError(error -> { + if (error instanceof NoResourceFoundException) { + log.info("No Exam found for rollback."); + } else { + log.error("Failed to rollback auto Exam import: ", error); + } + }); }) - .getOrThrow(); + .getOr(null); - log.info("Auto import of exam successful: {}", exam); + if (exam != null) { + log.info("Auto import of exam successful: {}", exam); + } } @RequestMapping( @@ -181,7 +191,7 @@ public class LmsIntegrationController { @RequestParam(name = API.LMS_FULL_INTEGRATION_TIME_ZONE, required = false) final String timezone, final HttpServletResponse response) { - final FullLmsIntegrationService.AdHocAccountData adHocAccountData = new FullLmsIntegrationService.AdHocAccountData( + final AdHocAccountData adHocAccountData = new AdHocAccountData( userId, username, userMail,