From d2036a85980731d6f119524282a28986e92758f9 Mon Sep 17 00:00:00 2001 From: anhefti Date: Tue, 22 Jun 2021 14:26:08 +0200 Subject: [PATCH] disallow proctoring service change if there are existing proctoring rooms --- .../model/exam/ProctoringServiceSettings.java | 10 ++++++++ .../gui/content/ExamProctoringSettings.java | 10 ++++++-- .../dao/RemoteProctoringRoomDAO.java | 6 +++++ .../dao/impl/RemoteProctoringRoomDAOImpl.java | 9 +++++++ .../exam/impl/ExamAdminServiceImpl.java | 5 ++++ .../proctoring/ZoomProctoringService.java | 24 ------------------ .../admin/ExamProctoringRoomServiceTest.java | 25 ++++++++++++++----- 7 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java index 915e99c8..df0458c9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java @@ -36,6 +36,7 @@ public class ProctoringServiceSettings implements Entity { public static final String ATTR_APP_SECRET = "appSecret"; public static final String ATTR_COLLECTING_ROOM_SIZE = "collectingRoomSize"; public static final String ATTR_COLLECT_ALL_ROOM_NAME = "collectAllRoomName"; + public static final String ATTR_SERVICE_IN_USE = "serviceInUse"; @JsonProperty(Domain.EXAM.ATTR_ID) public final Long examId; @@ -59,6 +60,9 @@ public class ProctoringServiceSettings implements Entity { @JsonProperty(ATTR_COLLECTING_ROOM_SIZE) public final Integer collectingRoomSize; + @JsonProperty(ATTR_SERVICE_IN_USE) + public final Boolean serviceInUse; + @JsonCreator public ProctoringServiceSettings( @JsonProperty(Domain.EXAM.ATTR_ID) final Long examId, @@ -66,6 +70,7 @@ public class ProctoringServiceSettings implements Entity { @JsonProperty(ATTR_SERVER_TYPE) final ProctoringServerType serverType, @JsonProperty(ATTR_SERVER_URL) final String serverURL, @JsonProperty(ATTR_COLLECTING_ROOM_SIZE) final Integer collectingRoomSize, + @JsonProperty(ATTR_SERVICE_IN_USE) final Boolean serviceInUse, @JsonProperty(ATTR_APP_KEY) final String appKey, @JsonProperty(ATTR_APP_SECRET) final CharSequence appSecret) { @@ -74,6 +79,7 @@ public class ProctoringServiceSettings implements Entity { this.serverType = (serverType != null) ? serverType : ProctoringServerType.JITSI_MEET; this.serverURL = serverURL; this.collectingRoomSize = (collectingRoomSize != null) ? collectingRoomSize : 20; + this.serviceInUse = serviceInUse; this.appKey = appKey; this.appSecret = appSecret; } @@ -121,6 +127,10 @@ public class ProctoringServiceSettings implements Entity { return this.appSecret; } + public Boolean getServiceInUse() { + return this.serviceInUse; + } + @Override public int hashCode() { final int prime = 31; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamProctoringSettings.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamProctoringSettings.java index 278e27c7..201df344 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamProctoringSettings.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamProctoringSettings.java @@ -128,8 +128,8 @@ public class ExamProctoringSettings { final boolean enabled = BooleanUtils.toBoolean( form.getFieldValue(ProctoringServiceSettings.ATTR_ENABLE_PROCTORING)); - final ProctoringServerType serverType = ProctoringServerType.valueOf( - form.getFieldValue(ProctoringServiceSettings.ATTR_SERVER_TYPE)); + final ProctoringServerType serverType = ProctoringServerType + .valueOf(form.getFieldValue(ProctoringServiceSettings.ATTR_SERVER_TYPE)); examProctoring = new ProctoringServiceSettings( Long.parseLong(entityKey.modelId), @@ -137,6 +137,7 @@ public class ExamProctoringSettings { serverType, form.getFieldValue(ProctoringServiceSettings.ATTR_SERVER_URL), Integer.parseInt(form.getFieldValue(ProctoringServiceSettings.ATTR_COLLECTING_ROOM_SIZE)), + false, form.getFieldValue(ProctoringServiceSettings.ATTR_APP_KEY), form.getFieldValue(ProctoringServiceSettings.ATTR_APP_SECRET)); @@ -263,6 +264,11 @@ public class ExamProctoringSettings { .build(); + if (proctoringSettings.serviceInUse) { + formHandle.getForm().getFieldInput(ProctoringServiceSettings.ATTR_SERVER_TYPE).setEnabled(false); + formHandle.getForm().getFieldInput(ProctoringServiceSettings.ATTR_SERVER_URL).setEnabled(false); + } + return () -> formHandle; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/RemoteProctoringRoomDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/RemoteProctoringRoomDAO.java index 2b8f78a7..aef5f198 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/RemoteProctoringRoomDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/RemoteProctoringRoomDAO.java @@ -19,6 +19,12 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring.New /** Data access for RemoteProctoringRoom domain objects. */ public interface RemoteProctoringRoomDAO { + /** Indicates if there is already any proctoring service in use for the specified exam + * + * @param examId the exam identifier + * @return Result refer to the indication or to an error when happened. */ + Result isServiceInUse(Long examId); + /** Get all collecting room records that exists for a given exam. * * @param examId the exam identifier diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/RemoteProctoringRoomDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/RemoteProctoringRoomDAOImpl.java index fe0c239f..fdbb61b3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/RemoteProctoringRoomDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/RemoteProctoringRoomDAOImpl.java @@ -56,6 +56,15 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO { this.remoteProctoringRoomRecordMapper = remoteProctoringRoomRecordMapper; } + @Override + public Result isServiceInUse(final Long examId) { + return Result.tryCatch(() -> this.remoteProctoringRoomRecordMapper + .countByExample() + .where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId)) + .build() + .execute() > 0); + } + @Override @Transactional(readOnly = true) public Result> getCollectingRooms(final Long examId) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamAdminServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamAdminServiceImpl.java index c8a68897..377986dc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamAdminServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/impl/ExamAdminServiceImpl.java @@ -43,6 +43,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.AdditionalAttribut import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; @@ -62,6 +63,7 @@ public class ExamAdminServiceImpl implements ExamAdminService { private final JSONMapper jsonMapper; private final Cryptor cryptor; private final ExamProctoringServiceFactory examProctoringServiceFactory; + private final RemoteProctoringRoomDAO remoteProctoringRoomDAO; private final String defaultIndicatorName; private final String defaultIndicatorType; @@ -76,6 +78,7 @@ public class ExamAdminServiceImpl implements ExamAdminService { final JSONMapper jsonMapper, final Cryptor cryptor, final ExamProctoringServiceFactory examProctoringServiceFactory, + final RemoteProctoringRoomDAO remoteProctoringRoomDAO, @Value("${sebserver.webservice.api.exam.indicator.name:Ping}") final String defaultIndicatorName, @Value("${sebserver.webservice.api.exam.indicator.type:LAST_PING}") final String defaultIndicatorType, @Value("${sebserver.webservice.api.exam.indicator.color:b4b4b4}") final String defaultIndicatorColor, @@ -88,6 +91,7 @@ public class ExamAdminServiceImpl implements ExamAdminService { this.jsonMapper = jsonMapper; this.cryptor = cryptor; this.examProctoringServiceFactory = examProctoringServiceFactory; + this.remoteProctoringRoomDAO = remoteProctoringRoomDAO; this.defaultIndicatorName = defaultIndicatorName; this.defaultIndicatorType = defaultIndicatorType; @@ -199,6 +203,7 @@ public class ExamAdminServiceImpl implements ExamAdminService { getServerType(mapping), getString(mapping, ProctoringServiceSettings.ATTR_SERVER_URL), getCollectingRoomSize(mapping), + this.remoteProctoringRoomDAO.isServiceInUse(examId).getOr(true), getString(mapping, ProctoringServiceSettings.ATTR_APP_KEY), getString(mapping, ProctoringServiceSettings.ATTR_APP_SECRET)); }); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java index b98f30b6..ebccb028 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java @@ -170,30 +170,6 @@ public class ZoomProctoringService implements ExamProctoringService { throw new APIMessageException( APIMessage.ErrorMessage.BINDING_ERROR, String.valueOf(result.getStatusCode())); - } else { - // TODO this is just for cleaning up along development process. - // Remove this before finish up the Zoom integration - - try { - final ProctoringServiceSettings encryptedSettings = new ProctoringServiceSettings( - proctoringSettings.examId, - proctoringSettings.enableProctoring, - proctoringSettings.serverType, - proctoringSettings.serverURL, - proctoringSettings.collectingRoomSize, - proctoringSettings.appKey, - this.cryptor - .encrypt(proctoringSettings.appSecret) - .getOrThrow()); - - disposeServiceRoomsForExam( - proctoringSettings.examId, - encryptedSettings) - .getOrThrow(); - - } catch (final Exception e) { - log.error("Failed to dev-cleanup rooms: ", e); - } } } catch (final Exception e) { diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamProctoringRoomServiceTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamProctoringRoomServiceTest.java index babb1e5e..a8727a76 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamProctoringRoomServiceTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamProctoringRoomServiceTest.java @@ -20,6 +20,8 @@ import org.springframework.test.context.jdbc.Sql; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; +import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; +import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService; @@ -60,16 +62,27 @@ public class ExamProctoringRoomServiceTest extends AdministrationAPIIntegrationT this.examAdminService.saveProctoringServiceSettings( 2L, new ProctoringServiceSettings( - 2L, true, ProctoringServerType.JITSI_MEET, "http://jitsi.ch", 1, + 2L, true, ProctoringServerType.JITSI_MEET, "http://jitsi.ch", 1, false, "app-key", "app.secret")); assertTrue(this.examAdminService.isProctoringEnabled(2L).get()); } -// @Test -// @Order(3) -// public void test03_addClientConnection() { -// clientConnectionDAO.createNew(new ClientConnection(null, 1L, 2L, ConnectionStatus.CONNECTION_REQUESTED, CONNECTION_TOKEN_1)) -// } + @Test + @Order(3) + public void test03_addClientConnection() { + final Result createNew = this.clientConnectionDAO.createNew(new ClientConnection( + null, + 1L, + 2L, + ConnectionStatus.CONNECTION_REQUESTED, + CONNECTION_TOKEN_1, + "", + "", + false, + "", + null)); + assertFalse(createNew.hasError()); + } }