From 3dddaf9051b4e2ae2c7ebed5aaa22eced05f25b1 Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 24 Feb 2021 16:38:30 +0100 Subject: [PATCH] SEBSERV-148 refactoring and backend --- .../seb/sebserver/gbl/api/APIMessage.java | 4 +- .../model/exam/ProctoringServiceSettings.java | 3 +- .../seb/sebserver/gui/ProctoringServlet.java | 27 +++++--- .../seb/sebserver/gui/form/FormHandle.java | 49 ++++++++----- .../servicelayer/exam/ExamAdminService.java | 4 +- .../exam/impl/ExamAdminServiceImpl.java | 20 +++--- .../session/ExamProctoringService.java | 4 +- .../impl/ExamJITSIProctoringService.java | 53 ++++++++++++--- .../impl/ExamZOOMProctoringService.java | 68 +++++++++++++++++++ .../api/ExamAdministrationController.java | 7 +- src/main/resources/messages.properties | 5 +- .../impl/ExamJITSIProctoringServiceTest.java | 6 +- 12 files changed, 195 insertions(+), 55 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamZOOMProctoringService.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java index 85410d7f..a9609191 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java @@ -52,7 +52,9 @@ public class APIMessage implements Serializable { EXAM_CONSISTENCY_VALIDATION_CONFIG("1401", HttpStatus.OK, "No SEB Exam Configuration defined for the Exam"), EXAM_CONSISTENCY_VALIDATION_SEB_RESTRICTION("1402", HttpStatus.OK, "SEB restriction API available but Exam not restricted on LMS side yet"), - EXAM_CONSISTENCY_VALIDATION_INDICATOR("1403", HttpStatus.OK, "No Indicator defined for the Exam"); + EXAM_CONSISTENCY_VALIDATION_INDICATOR("1403", HttpStatus.OK, "No Indicator defined for the Exam"), + + BINDING_ERROR("1500", HttpStatus.BAD_REQUEST, "External binding error"); public final String messageCode; public final HttpStatus httpStatus; 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 bf06ba20..915e99c8 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 @@ -25,7 +25,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.ValidProctoringS public class ProctoringServiceSettings implements Entity { public enum ProctoringServerType { - JITSI_MEET + JITSI_MEET, + ZOOM } public static final String ATTR_ENABLE_PROCTORING = "enableProctoring"; 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 7d8e492a..5a3b1944 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/ProctoringServlet.java @@ -35,7 +35,7 @@ public class ProctoringServlet extends HttpServlet { private static final long serialVersionUID = 3475978419653411800L; // @formatter:off - private static final String HTML = + private static final String JITSI_WINDOW_HTML = "" + "" + "" + @@ -103,15 +103,22 @@ public class ProctoringServlet extends HttpServlet { (ProctoringWindowData) httpSession .getAttribute(ProctoringGUIService.SESSION_ATTR_PROCTORING_DATA); - final String script = String.format( - HTML, - proctoringData.connectionData.serverHost, - proctoringData.connectionData.roomName, - proctoringData.connectionData.accessToken, - proctoringData.connectionData.serverHost, - proctoringData.connectionData.subject); - resp.getOutputStream().println(script); - + switch (proctoringData.connectionData.proctoringServerType) { + case JITSI_MEET: { + final String script = String.format( + JITSI_WINDOW_HTML, + proctoringData.connectionData.serverHost, + proctoringData.connectionData.roomName, + proctoringData.connectionData.accessToken, + proctoringData.connectionData.serverHost, + proctoringData.connectionData.subject); + resp.getOutputStream().println(script); + break; + } + default: + throw new RuntimeException( + "Unsupported proctoring server type: " + proctoringData.connectionData.proctoringServerType); + } } private boolean isAuthenticated( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java index cb8e12c5..80e2f73c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java @@ -8,13 +8,13 @@ package ch.ethz.seb.sebserver.gui.form; +import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.lang3.StringUtils; -import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.EntityType; @@ -35,8 +35,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; public class FormHandle { - private static final Logger log = LoggerFactory.getLogger(FormHandle.class); - public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "sebserver.form.validation.fieldError."; private final PageService pageService; @@ -137,30 +135,49 @@ public class FormHandle { public boolean handleError(final Exception error) { if (error instanceof RestCallError) { - ((RestCallError) error) + + final List fieldValidationErrors = ((RestCallError) error) .getErrorMessages() .stream() .filter(APIMessage.ErrorMessage.FIELD_VALIDATION::isOf) + .collect(Collectors.toList()); + + final List noneFieldValidationErrors = ((RestCallError) error) + .getErrorMessages() + .stream() + .filter(message -> !APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(message)) + .collect(Collectors.toList()); + + fieldValidationErrors + .stream() .map(FieldValidationError::new) .forEach(fve -> this.form.process( name -> name.equals(fve.fieldName), fieldAccessor -> showValidationError(fieldAccessor, fve))); + + if (!noneFieldValidationErrors.isEmpty()) { + handleUnexpectedError(new RestCallError( + PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, + noneFieldValidationErrors)); + return false; + } return true; } else { - log.error("Unexpected error while trying to post form: {}", error.getMessage()); - final EntityType resultType = this.post.getEntityType(); - if (resultType != null) { - this.pageContext.notifySaveError(resultType, error); - } else { - this.pageContext.notifyError( - new LocTextKey(PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, Constants.EMPTY_NOTE), - error); - } - + handleUnexpectedError(error); return false; } } + private void handleUnexpectedError(final Exception error) { + if (this.post != null && this.post.getEntityType() != null) { + this.pageContext.notifySaveError(this.post.getEntityType(), error); + } else { + this.pageContext.notifyError( + new LocTextKey(PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, StringUtils.EMPTY), + error); + } + } + public boolean hasAnyError() { return this.form.hasAnyError(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamAdminService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamAdminService.java index 6309ae73..c1e0c0bc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamAdminService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/exam/ExamAdminService.java @@ -61,11 +61,11 @@ public interface ExamAdminService { /** Save the given proctoring service settings for an existing Exam. * * @param examId the exam identifier - * @param examProctoring The proctoring service settings to save for the exam + * @param proctoringServiceSettings The proctoring service settings to save for the exam * @return Result refer to saved proctoring service settings or to an error when happened. */ Result saveProctoringServiceSettings( Long examId, - ProctoringServiceSettings examProctoring); + ProctoringServiceSettings proctoringServiceSettings); /** This indicates if proctoring is set and enabled for a certain exam. * 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 0aebdfce..2e3eb171 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 @@ -206,47 +206,49 @@ public class ExamAdminServiceImpl implements ExamAdminService { @Override @Transactional - public Result saveProctoringServiceSettings(final Long examId, - final ProctoringServiceSettings examProctoring) { + public Result saveProctoringServiceSettings( + final Long examId, + final ProctoringServiceSettings proctoringServiceSettings) { + return Result.tryCatch(() -> { this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_ENABLE_PROCTORING, - String.valueOf(examProctoring.enableProctoring)); + String.valueOf(proctoringServiceSettings.enableProctoring)); this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_SERVER_TYPE, - examProctoring.serverType.name()); + proctoringServiceSettings.serverType.name()); this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_SERVER_URL, - examProctoring.serverURL); + proctoringServiceSettings.serverURL); this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_COLLECTING_ROOM_SIZE, - String.valueOf(examProctoring.collectingRoomSize)); + String.valueOf(proctoringServiceSettings.collectingRoomSize)); this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_APP_KEY, - examProctoring.appKey); + proctoringServiceSettings.appKey); this.additionalAttributesDAO.saveAdditionalAttribute( EntityType.EXAM, examId, ProctoringServiceSettings.ATTR_APP_SECRET, - this.cryptor.encrypt(examProctoring.appSecret).toString()); + this.cryptor.encrypt(proctoringServiceSettings.appSecret).toString()); - return examProctoring; + return proctoringServiceSettings; }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ExamProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ExamProctoringService.java index 8bab8426..71150033 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ExamProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/ExamProctoringService.java @@ -26,9 +26,9 @@ public interface ExamProctoringService { /** Use this to test the proctoring service settings against the remote proctoring server. * - * @param examProctoring the settings to test + * @param proctoringSettings the settings to test * @return Result refer to true if the settings are correct and the proctoring server can be accessed. */ - Result testExamProctoring(final ProctoringServiceSettings examProctoring); + Result testExamProctoring(final ProctoringServiceSettings proctoringSettings); /** Gets the room connection data for a certain room for the proctor. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringService.java index 132baeef..5e72f04b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringService.java @@ -24,14 +24,22 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService; import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.api.APIMessage; +import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; +import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; +import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection; 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.exam.ProctoringRoomConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType; @@ -50,6 +58,10 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructio @WebServiceProfile public class ExamJITSIProctoringService implements ExamProctoringService { + private static final String SEB_SERVER_KEY = "seb-server"; + + private static final String SEB_CLIENT_KEY = "seb-client"; + private static final Logger log = LoggerFactory.getLogger(ExamJITSIProctoringService.class); private static final String JITSI_ACCESS_TOKEN_HEADER = @@ -63,19 +75,22 @@ public class ExamJITSIProctoringService implements ExamProctoringService { private final ExamSessionService examSessionService; private final SEBClientInstructionService sebClientInstructionService; private final Cryptor cryptor; + private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; protected ExamJITSIProctoringService( final RemoteProctoringRoomDAO remoteProctoringRoomDAO, final AuthorizationService authorizationService, final ExamSessionService examSessionService, final SEBClientInstructionService sebClientInstructionService, - final Cryptor cryptor) { + final Cryptor cryptor, + final ClientHttpRequestFactoryService clientHttpRequestFactoryService) { this.remoteProctoringRoomDAO = remoteProctoringRoomDAO; this.authorizationService = authorizationService; this.examSessionService = examSessionService; this.sebClientInstructionService = sebClientInstructionService; this.cryptor = cryptor; + this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; } @Override @@ -84,9 +99,31 @@ public class ExamJITSIProctoringService implements ExamProctoringService { } @Override - public Result testExamProctoring(final ProctoringServiceSettings examProctoring) { - // TODO Auto-generated method stub - return null; + public Result testExamProctoring(final ProctoringServiceSettings proctoringSettings) { + return Result.tryCatch(() -> { + if (proctoringSettings.serverURL != null && proctoringSettings.serverURL.contains("?")) { + throw new FieldValidationException( + "serverURL", + "proctoringSettings:serverURL:invalidURL"); + } + + final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService + .getClientHttpRequestFactory() + .getOrThrow(); + + try { + final RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory); + final ResponseEntity result = + restTemplate.getForEntity(proctoringSettings.serverURL, String.class); + if (result.getStatusCode() != HttpStatus.OK) { + throw new APIMessageException(APIMessage.ErrorMessage.BINDING_ERROR); + } + } catch (final Exception e) { + throw new APIMessageException(APIMessage.ErrorMessage.BINDING_ERROR, e.getMessage()); + } + + return true; + }); } @Override @@ -220,7 +257,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService { proctoringSettings.appKey, proctoringSettings.getAppSecret(), this.authorizationService.getUserService().getCurrentUser().getUsername(), - "seb-server", + SEB_SERVER_KEY, roomName, subject, forExam(proctoringSettings), @@ -247,7 +284,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService { proctoringSettings.appKey, proctoringSettings.getAppSecret(), clientConnection.clientConnection.userSessionId, - "seb-client", + SEB_CLIENT_KEY, roomName, subject, forExam(proctoringSettings), @@ -276,7 +313,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService { proctoringSettings.appKey, proctoringSettings.getAppSecret(), connectionData.clientConnection.userSessionId, - "seb-client", + SEB_CLIENT_KEY, roomName, subject, expTime, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamZOOMProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamZOOMProctoringService.java new file mode 100644 index 00000000..eb0eb608 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamZOOMProctoringService.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021 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.session.impl; + +import java.util.Collection; + +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection; +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.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringService; + +@Lazy +@Service +@WebServiceProfile +public class ExamZOOMProctoringService implements ExamProctoringService { + + @Override + public ProctoringServerType getType() { + return ProctoringServerType.ZOOM; + } + + @Override + public Result testExamProctoring(final ProctoringServiceSettings examProctoring) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Result getProctorRoomConnection( + final ProctoringServiceSettings proctoringSettings, + final String roomName, + final String subject) { + + // TODO Auto-generated method stub + return null; + } + + @Override + public Result sendJoinRoomToClients( + final ProctoringServiceSettings proctoringSettings, + final Collection clientConnectionTokens, + final String roomName, final String subject) { + + // TODO Auto-generated method stub + return null; + } + + @Override + public Result sendJoinCollectingRoomToClients( + final ProctoringServiceSettings proctoringSettings, + final Collection clientConnectionTokens) { + + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java index 68cea1cf..86fdb58c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java @@ -411,13 +411,16 @@ public class ExamAdministrationController extends EntityController { required = true, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, @PathVariable(API.PARAM_MODEL_ID) final Long examId, - @Valid @RequestBody final ProctoringServiceSettings examProctoring) { + @Valid @RequestBody final ProctoringServiceSettings proctoringServiceSettings) { checkModifyPrivilege(institutionId); return this.entityDAO.byPK(examId) .flatMap(this.authorization::checkModify) .map(exam -> { - this.examAdminService.saveProctoringServiceSettings(examId, examProctoring); + this.examAdminService.getExamProctoringService(proctoringServiceSettings.serverType) + .flatMap(service -> service.testExamProctoring(proctoringServiceSettings)) + .getOrThrow(); + this.examAdminService.saveProctoringServiceSettings(examId, proctoringServiceSettings); return exam; }) .flatMap(this.userActivityLogDAO::logModify) diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 862ff8e0..33f59347 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -653,7 +653,10 @@ sebserver.exam.proctoring.form.secret=Secret sebserver.exam.proctoring.form.secret.tooltip=The secret used to access the proctoring service sebserver.exam.proctoring.type.servertype.JITSI_MEET=Jitsi Meet Server -sebserver.exam.proctoring.type.servertype.JITSI_MEET.tooltip=Use a Jitsi Meet Server for proctoring +sebserver.exam.proctoring.type.servertype.JITSI_MEET.tooltip=Use a Jitsi Meet server for proctoring +sebserver.exam.proctoring.type.servertype.ZOOM=Zoom Server +sebserver.exam.proctoring.type.servertype.ZOOM.tooltip=Use a Zoom meeting server for proctoring + ################################ # Connection Configuration diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringServiceTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringServiceTest.java index 4a368c3b..1d95ddae 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringServiceTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamJITSIProctoringServiceTest.java @@ -17,8 +17,8 @@ import java.security.NoSuchAlgorithmException; import org.junit.Test; import org.mockito.Mockito; -import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection; +import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.util.Cryptor; public class ExamJITSIProctoringServiceTest { @@ -28,7 +28,7 @@ public class ExamJITSIProctoringServiceTest { final Cryptor cryptorMock = Mockito.mock(Cryptor.class); Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn("fbvgeghergrgrthrehreg123"); final ExamJITSIProctoringService examJITSIProctoringService = - new ExamJITSIProctoringService(null, null, null, null, cryptorMock); + new ExamJITSIProctoringService(null, null, null, null, cryptorMock, null); String accessToken = examJITSIProctoringService.createPayload( "test-app", @@ -62,7 +62,7 @@ public class ExamJITSIProctoringServiceTest { final Cryptor cryptorMock = Mockito.mock(Cryptor.class); Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn("fbvgeghergrgrthrehreg123"); final ExamJITSIProctoringService examJITSIProctoringService = - new ExamJITSIProctoringService(null, null, null, null, cryptorMock); + new ExamJITSIProctoringService(null, null, null, null, cryptorMock, null); final ProctoringRoomConnection data = examJITSIProctoringService.createProctoringConnection( ProctoringServerType.JITSI_MEET, "connectionToken",