From 9bda8630f648b979d328fb4b8cb1c77f248f74e8 Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 29 Nov 2023 14:21:28 +0100 Subject: [PATCH] SEBSERV-435 improved SEB Server SPS user account sync --- .../MonitoringProctoringService.java | 4 +- .../servicelayer/dao/impl/UserDAOImpl.java | 2 - .../session/ScreenProctoringService.java | 3 ++ .../impl/SEBClientConnectionServiceImpl.java | 5 +- .../ScreenProctoringAPIBinding.java | 46 +++++++++++++++++-- .../ScreenProctoringServiceImpl.java | 14 ++++++ .../weblayer/api/UserAccountController.java | 9 ++++ .../config/application-dev-ws.properties | 2 +- .../integration/UseCasesIntegrationTest.java | 10 ++-- 9 files changed, 81 insertions(+), 14 deletions(-) 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 491e6b1f..3a5fa3ce 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 @@ -180,7 +180,9 @@ public class MonitoringProctoringService { proctoringGUIService, room)); - if (proctoringSettings.enabledFeatures.contains(ProctoringFeature.TOWN_HALL)) { + if (BooleanUtils.isTrue(proctoringSettings.enableProctoring) && + proctoringSettings.enabledFeatures.contains(ProctoringFeature.TOWN_HALL)) { + updateTownhallButton(proctoringGUIService, pageContext); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java index 63586188..6f51b102 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDAOImpl.java @@ -499,8 +499,6 @@ public class UserDAOImpl implements UserDAO { this.userRecordMapper .selectByExample() .where(UserRecordDynamicSqlSupport.username, isEqualTo(username)) - .and(UserRecordDynamicSqlSupport.active, - isEqualTo(BooleanUtils.toInteger(true))) .build() .execute()); } 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 f6427c55..2415ec6a 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 @@ -90,4 +90,7 @@ public interface ScreenProctoringService extends SessionUpdateTask { @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) void synchronizeSPSUser(final String userUUID); + @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) + void deleteSPSUser(String userUUID); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java index 9eb75d05..eee9e62e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java @@ -494,8 +494,9 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic .getConnectionData(connectionToken) .getOrThrow(); - // A connection can only be disabled if we have a missing ping - if (!BooleanUtils.isTrue(connectionData.getMissingPing())) { + // A connection can only be disabled if we have a missing ping or for closed connections + if (connectionData.clientConnection.status != ConnectionStatus.CLOSED && + !BooleanUtils.isTrue(connectionData.getMissingPing())) { return connectionData.clientConnection; } 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 0b8bbf69..2bc02ac0 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 @@ -363,7 +363,7 @@ class ScreenProctoringAPIBinding { .toUriString(); final ResponseEntity exchange = apiTemplate.exchange( - uri, HttpMethod.POST, null, apiTemplate.getHeaders()); + uri, HttpMethod.GET, null, apiTemplate.getHeaders()); if (exchange.getStatusCode() == HttpStatus.OK) { log.info("Synchronize SPS user account for SEB Server user account with id: {} ", userUUID); @@ -386,6 +386,30 @@ class ScreenProctoringAPIBinding { log.error("Failed to synchronize user accounts with SPS for exam: {}", exam); } } + void deleteSPSUser(final String userUUID) { + try { + + final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(null); + + final String uri = UriComponentsBuilder + .fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL()) + .path(SPS_API.USER_ACCOUNT_ENDPOINT + userUUID) + .build() + .toUriString(); + + final ResponseEntity exchange = apiTemplate.exchange( + uri, HttpMethod.DELETE, null, apiTemplate.getHeaders()); + + if (exchange.getStatusCode() == HttpStatus.OK) { + log.info("Successfully deleted User Account on SPS for user: {}", userUUID); + } else { + log.error("Failed to delete user account on SPS for user: {} response: {}", userUUID, exchange); + } + + } catch (final Exception e) { + log.error("Failed to delete user account on SPS for user: {}", userUUID); + } + } /** This is called when an exam has changed its parameter and needs data update on SPS side * @@ -583,7 +607,7 @@ class ScreenProctoringAPIBinding { .byModelId(userUUID) .getOrThrow(); final SEBServerUser accountInfo = this.userDAO - .sebServerUserByUsername(userInfo.name) + .sebServerUserByUsername(userInfo.username) .getOrThrow(); final UserMod userMod = getUserModifications(userInfo, accountInfo); @@ -600,8 +624,24 @@ class ScreenProctoringAPIBinding { if (exchange.getStatusCode() != HttpStatus.OK) { log.warn("Failed to synchronize user account on SPS: {}", exchange); } else { - log.info("Successfully synchronize user account on SPS for user: "); + log.info("Successfully synchronize user account on SPS for user: {}", userUUID); + } + // sync activity + final String activityURI = UriComponentsBuilder + .fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL()) + .path(SPS_API.USER_ACCOUNT_ENDPOINT) + .pathSegment(userUUID) + .path(BooleanUtils.isTrue(userInfo.active) ? "/active" : "/inactive") + .build() + .toUriString(); + final ResponseEntity activityRequest = apiTemplate.exchange( + activityURI, HttpMethod.POST, jsonBody, apiTemplate.getHeaders()); + + if (activityRequest.getStatusCode() != HttpStatus.OK) { + 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) { 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 a33f4fa8..4573371d 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 @@ -15,12 +15,14 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import ch.ethz.seb.sebserver.gbl.api.APIMessage; @@ -262,6 +264,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService { } @Override + @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) public void synchronizeSPSUser(final String userUUID) { if (!webserviceInfo.getScreenProctoringServiceBundle().bundled) { @@ -271,6 +274,17 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService { this.screenProctoringAPIBinding.synchronizeUserAccount(userUUID); } + @Override + @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) + public void deleteSPSUser(final String userUUID) { + + if (!webserviceInfo.getScreenProctoringServiceBundle().bundled) { + return; + } + + this.screenProctoringAPIBinding.deleteSPSUser(userUUID); + } + @Override public void notifyExamStarted(final ExamStartedEvent event) { final Exam exam = event.exam; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 4e1feb6e..8fbbab22 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -15,6 +15,8 @@ import java.util.List; import javax.validation.Valid; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; +import ch.ethz.seb.sebserver.gbl.util.Pair; import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService; import org.mybatis.dynamic.sql.SqlTable; import org.springframework.beans.factory.annotation.Qualifier; @@ -156,6 +158,13 @@ public class UserAccountController extends ActivatableEntityController> notifyDeleted(final Pair pair) { + final Result> result = super.notifyDeleted(pair); + this.screenProctoringService.deleteSPSUser(pair.a.uuid); + return result; + } + @RequestMapping( path = API.PASSWORD_PATH_SEGMENT, method = RequestMethod.PUT, diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties index 721587a1..595e7aff 100644 --- a/src/main/resources/config/application-dev-ws.properties +++ b/src/main/resources/config/application-dev-ws.properties @@ -64,6 +64,6 @@ management.endpoints.web.exposure.include=logfile,loggers,jolokia management.endpoints.web.path-mapping.jolokia=jmx sebserver.feature.seb.screenProctoring.bundled=true -sebserver.feature.seb.screenProctoring.bundled.url=localhost:8090 +sebserver.feature.seb.screenProctoring.bundled.url=http://localhost:8090 sebserver.feature.seb.screenProctoring.bundled.clientId=sebserverClient sebserver.feature.seb.screenProctoring.bundled.sebserveraccount.username=SEBServerAPIAccount \ No newline at end of file diff --git a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java index c8708c22..8e3e981f 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java @@ -2437,7 +2437,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { connections = connectionsCall.get(); assertFalse(connections.isEmpty()); conData = connections.iterator().next(); - assertEquals("CLOSED", conData.clientConnection.status.name()); + assertEquals("DISABLED", conData.clientConnection.status.name()); // get client logs final Result> clientLogPage = restService @@ -2520,7 +2520,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { assertFalse(ccDataPage.content.isEmpty()); final ClientConnectionData clientConnectionData = ccDataPage.content.get(0); assertNotNull(clientConnectionData); - assertEquals("CLOSED", clientConnectionData.clientConnection.status.toString()); + assertEquals("DISABLED", clientConnectionData.clientConnection.status.toString()); connectionDatacall = restService .getBuilder(GetFinishedExamClientConnectionPage.class) @@ -2552,9 +2552,9 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { @Order(18) // ************************************* // Use Case 18: Login as examAdmin2 and get dependencies of examAdmin2 - // - Get all dependencies and check correctnes. - // - Get all dependencies including only Exam Configuration and check correctnes. - // - Get all dependencies including only ClientConnection and check correctnes. + // - Get all dependencies and check correctness. + // - Get all dependencies including only Exam Configuration and check correctness. + // - Get all dependencies including only ClientConnection and check correctness. public void testUsecase18_UserDependencies() throws IOException { final RestServiceImpl restService = createRestServiceForUser( "examAdmin2",