From 6e5d5e77103cddde668308864707450814bdc76d Mon Sep 17 00:00:00 2001 From: anhefti Date: Thu, 2 Nov 2023 15:01:29 +0100 Subject: [PATCH] SEBSERV-435 fixes and preparing integration configuration --- .../seb/sebserver/gui/ProctoringServlet.java | 18 +++++++-------- .../servicelayer/dao/ClientConnectionDAO.java | 5 +++++ .../dao/impl/ClientConnectionDAOImpl.java | 17 +++++++++++++- .../impl/SEBClientConnectionServiceImpl.java | 9 ++++---- .../impl/SEBClientPingBatchService.java | 22 +++++++++++++------ .../impl/SEBClientPingServiceFactory.java | 2 +- .../ScreenProctoringAPIBinding.java | 2 ++ .../ScreenProctoringServiceImpl.java | 4 ++++ .../config/application-dev-ws.properties | 1 + .../resources/config/application.properties | 3 +++ 10 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java b/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java index 2fe48afe..209eca4c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java @@ -94,15 +94,15 @@ public class ProctoringServlet extends HttpServlet { // https://stackoverflow.com/questions/46582/response-redirect-with-post-instead-of-get final StringBuilder sb = new StringBuilder(); - sb.append(""); - sb.append(""); - sb.append("
"); - sb.append(""); - sb.append(""); - sb.append("
"); - sb.append(""); - sb.append(""); +// sb.append(""); +// sb.append(""); +// sb.append("
"); +// sb.append(""); +// sb.append(""); +// sb.append("
"); +// sb.append(""); +// sb.append(""); resp.getOutputStream().println(sb.toString()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java index a848da17..3aaa232d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java @@ -148,6 +148,11 @@ public interface ClientConnectionDAO extends key = "#connectionToken") Result assignToScreenProctoringGroup(Long connectionId, String connectionToken, Long groupId); + @CacheEvict( + cacheNames = ExamSessionCacheService.CACHE_NAME_ACTIVE_CLIENT_CONNECTION, + key = "#connectionToken") + Result markScreenProcotringApplied(Long connectionId, String connectionToken); + /** Get a ClientConnection by connection token. * * @param connectionToken the connection token diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java index ffe7614e..24e06b18 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java @@ -532,7 +532,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { final List execute = this.clientConnectionRecordMapper .selectByExample() - .where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupId, isNull()) + .where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate, isNotEqualTo((byte) 0)) .and(ClientConnectionRecordDynamicSqlSupport.examId, isIn(examIds)) .and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name())) .build() @@ -571,6 +571,20 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { this.clientConnectionRecordMapper::update, ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord) .set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupId).equalTo(groupId) + //.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0) + .where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId)) + .build() + .execute(); + }) + .onError(TransactionHandler::rollback); + } + + @Override + public Result markScreenProcotringApplied(final Long connectionId, final String connectionToken) { + return Result.tryCatch(() -> { + UpdateDSL.updateWithMapper( + this.clientConnectionRecordMapper::update, + ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord) .set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0) .where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId)) .build() @@ -1136,4 +1150,5 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { .build() .execute(); } + } 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 a18e2ba7..c92ae347 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 @@ -381,12 +381,13 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic } } - // if screen proctoring enabled mark for screen proctoring update - // TODO - final Boolean proctoringEnabled = this.examAdminService .isProctoringEnabled(clientConnection.examId) .getOr(false); + final Boolean screenProctoringEnabled = this.examAdminService + .isScreenProctoringEnabled(clientConnection.examId) + .getOr(false); + final Long currentExamId = (examId != null) ? examId : clientConnection.examId; final String currentVdiConnectionId = (clientId != null) ? clientId @@ -410,7 +411,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic null, null, null, - null, + screenProctoringEnabled, null, proctoringEnabled, null, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingBatchService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingBatchService.java index e97c9233..804c75e6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingBatchService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingBatchService.java @@ -8,6 +8,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; +import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -41,8 +42,10 @@ public class SEBClientPingBatchService implements SEBClientPingService { private final ThreadPoolTaskScheduler threadPoolTaskScheduler; private final long schendulerInterval; + private final Set pingKeys = new HashSet<>(); private final Map pings = new ConcurrentHashMap<>(); private final Map instructions = new ConcurrentHashMap<>(); + private final Set confirmedInstructions = Collections.synchronizedSet(new HashSet<>()); private ScheduledFuture scheduleAtFixedRate = null; @@ -83,9 +86,10 @@ public class SEBClientPingBatchService implements SEBClientPingService { } try { - final Set connections = new HashSet<>(this.pings.keySet()); - - connections.stream().forEach(cid -> processPing( + this.pingKeys.clear(); + this.pingKeys.addAll(this.pings.keySet()); + //final Set connections = new HashSet<>(this.pings.keySet()); + this.pingKeys.stream().forEach(cid -> processPing( cid, this.pings.remove(cid), Utils.getMillisecondsNow())); @@ -111,10 +115,10 @@ public class SEBClientPingBatchService implements SEBClientPingService { System.out.println("************ put instructionConfirm: " + instructionConfirm + " instructions: " + this.instructions); this.pings.put(connectionToken, instructionConfirm); - // TODO is this a good idea or is there another better way to deal with instruction confirm synchronization? - if (instruction != null && instruction.contains("\"instruction-confirm\":\"" + instructionConfirm + "\"")) { - return null; - } +// // TODO is this a good idea or is there another better way to deal with instruction confirm synchronization? +// if (instruction != null && instruction.contains("\"instruction-confirm\":\"" + instructionConfirm + "\"")) { +// return null; +// } } else if (!this.pings.containsKey(connectionToken)) { this.pings.put(connectionToken, StringUtils.EMPTY); } @@ -147,6 +151,10 @@ public class SEBClientPingBatchService implements SEBClientPingService { this.sebClientInstructionService.confirmInstructionDone(connectionToken, instructionConfirm); } + if (this.instructions.containsKey(connectionToken)) { + return; + } + final String instructionJSON = this.sebClientInstructionService.getInstructionJSON(connectionToken); if (instructionJSON != null) { this.instructions.put(connectionToken, instructionJSON); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingServiceFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingServiceFactory.java index ad300f3d..31cd6ea7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingServiceFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientPingServiceFactory.java @@ -33,7 +33,7 @@ public class SEBClientPingServiceFactory { public SEBClientPingServiceFactory( final Collection serviceBeans, - @Value("${sebserver.webservice.api.exam.session.ping.service.type:BLOCKING}") final String serviceType) { + @Value("${sebserver.webservice.api.exam.session.ping.service.strategy:BLOCKING}") final String serviceType) { SEBClientPingService.PingServiceType serviceTypeToSet = SEBClientPingService.PingServiceType.BLOCKING; try { 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 a0052f46..b041355b 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 @@ -485,6 +485,8 @@ class ScreenProctoringAPIBinding { final ScreenProctoringGroup localGroup, final ClientConnectionRecord clientConnection) { + // TODO check if the Session with token UUID already exists and if true, return the token + final String token = clientConnection.getConnectionToken(); final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(examId); final String uri = UriComponentsBuilder 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 cefeb63a..6adc8a9e 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 @@ -316,6 +316,10 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService { // create instruction for SEB and add it to instruction queue for SEB connection registerJoinInstruction(ccRecord, spsSessionToken, group, runningExam); + this.clientConnectionDAO + .markScreenProcotringApplied(ccRecord.getId(), ccRecord.getConnectionToken()) + .getOrThrow(); + } catch (final Exception e) { log.error("Failed to apply screen proctoring session to SEB with connection: ", ccRecord, e); diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties index b49bad3b..a76d7f65 100644 --- a/src/main/resources/config/application-dev-ws.properties +++ b/src/main/resources/config/application-dev-ws.properties @@ -45,6 +45,7 @@ sebserver.webservice.api.exam.endpoint=/exam-api sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery sebserver.webservice.api.exam.endpoint.v1=${sebserver.webservice.api.exam.endpoint}/v1 sebserver.webservice.api.exam.event-handling-strategy=ASYNC_BATCH_STORE_STRATEGY +sebserver.webservice.api.exam.session.ping.service.strategy=BATCH sebserver.webservice.api.exam.enable-indicator-cache=true sebserver.webservice.api.exam.defaultPingInterval=1000 sebserver.webservice.api.pagination.maxPageSize=500 diff --git a/src/main/resources/config/application.properties b/src/main/resources/config/application.properties index 94629ad8..142d4a3a 100644 --- a/src/main/resources/config/application.properties +++ b/src/main/resources/config/application.properties @@ -65,4 +65,7 @@ sebserver.ssl.redirect.html.port=8080 # features sebserver.feature.seb.screenProctoring=false +sebserver.feature.seb.screenProctoring.bundled=true +sebserver.feature.seb.screenProctoring.bundled.clientId=sebserverClient +sebserver.feature.seb.screenProctoring.bundled.clientPassword=${sebserver.password} sebserver.feature.CollectingRoomStrategy.SEB-GROUP=false