SEBSERV-148 refactoring and backend
This commit is contained in:
parent
2f2a318f9d
commit
3dddaf9051
12 changed files with 195 additions and 55 deletions
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 =
|
||||
"<!DOCTYPE html>" +
|
||||
"<html>" +
|
||||
"<head>" +
|
||||
|
@ -103,15 +103,22 @@ public class ProctoringServlet extends HttpServlet {
|
|||
(ProctoringWindowData) httpSession
|
||||
.getAttribute(ProctoringGUIService.SESSION_ATTR_PROCTORING_DATA);
|
||||
|
||||
switch (proctoringData.connectionData.proctoringServerType) {
|
||||
case JITSI_MEET: {
|
||||
final String script = String.format(
|
||||
HTML,
|
||||
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(
|
||||
|
|
|
@ -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<T extends Entity> {
|
||||
|
||||
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,27 +135,46 @@ public class FormHandle<T extends Entity> {
|
|||
|
||||
public boolean handleError(final Exception error) {
|
||||
if (error instanceof RestCallError) {
|
||||
((RestCallError) error)
|
||||
|
||||
final List<APIMessage> fieldValidationErrors = ((RestCallError) error)
|
||||
.getErrorMessages()
|
||||
.stream()
|
||||
.filter(APIMessage.ErrorMessage.FIELD_VALIDATION::isOf)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<APIMessage> 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ProctoringServiceSettings> saveProctoringServiceSettings(
|
||||
Long examId,
|
||||
ProctoringServiceSettings examProctoring);
|
||||
ProctoringServiceSettings proctoringServiceSettings);
|
||||
|
||||
/** This indicates if proctoring is set and enabled for a certain exam.
|
||||
*
|
||||
|
|
|
@ -206,47 +206,49 @@ public class ExamAdminServiceImpl implements ExamAdminService {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<ProctoringServiceSettings> saveProctoringServiceSettings(final Long examId,
|
||||
final ProctoringServiceSettings examProctoring) {
|
||||
public Result<ProctoringServiceSettings> 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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Boolean> testExamProctoring(final ProctoringServiceSettings examProctoring);
|
||||
Result<Boolean> testExamProctoring(final ProctoringServiceSettings proctoringSettings);
|
||||
|
||||
/** Gets the room connection data for a certain room for the proctor.
|
||||
*
|
||||
|
|
|
@ -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<Boolean> testExamProctoring(final ProctoringServiceSettings examProctoring) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
public Result<Boolean> 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<String> 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,
|
||||
|
|
|
@ -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<Boolean> testExamProctoring(final ProctoringServiceSettings examProctoring) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ProctoringRoomConnection> getProctorRoomConnection(
|
||||
final ProctoringServiceSettings proctoringSettings,
|
||||
final String roomName,
|
||||
final String subject) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ProctoringRoomConnection> sendJoinRoomToClients(
|
||||
final ProctoringServiceSettings proctoringSettings,
|
||||
final Collection<String> clientConnectionTokens,
|
||||
final String roomName, final String subject) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Void> sendJoinCollectingRoomToClients(
|
||||
final ProctoringServiceSettings proctoringSettings,
|
||||
final Collection<String> clientConnectionTokens) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -411,13 +411,16 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
|||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue