proctoring refactoring

This commit is contained in:
anhefti 2021-02-16 11:50:30 +01:00
parent 3f2923da8f
commit 89ebf4da4b
12 changed files with 217 additions and 218 deletions

View file

@ -15,7 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class SEBProctoringConnectionData { public class SEBProctoringConnection {
public static final String ATTR_CONNECTION_TOKEN = "connectionToken"; public static final String ATTR_CONNECTION_TOKEN = "connectionToken";
public static final String ATTR_SERVER_HOST = "serverHost"; public static final String ATTR_SERVER_HOST = "serverHost";
@ -47,7 +47,7 @@ public class SEBProctoringConnectionData {
public final String accessToken; public final String accessToken;
@JsonCreator @JsonCreator
public SEBProctoringConnectionData( public SEBProctoringConnection(
@JsonProperty(ProctoringSettings.ATTR_SERVER_TYPE) final ProctoringServerType proctoringServerType, @JsonProperty(ProctoringSettings.ATTR_SERVER_TYPE) final ProctoringServerType proctoringServerType,
@JsonProperty(ATTR_CONNECTION_TOKEN) final String connectionToken, @JsonProperty(ATTR_CONNECTION_TOKEN) final String connectionToken,
@JsonProperty(ATTR_SERVER_HOST) final String serverHost, @JsonProperty(ATTR_SERVER_HOST) final String serverHost,

View file

@ -32,7 +32,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
@ -455,12 +455,12 @@ public class MonitoringClientConnection implements TemplateComposer {
if (roomOptional.isPresent()) { if (roomOptional.isPresent()) {
final RemoteProctoringRoom room = roomOptional.get(); final RemoteProctoringRoom room = roomOptional.get();
final SEBProctoringConnectionData proctoringConnectionData = this.pageService final SEBProctoringConnection proctoringConnectionData = this.pageService
.getRestService() .getRestService()
.getBuilder(GetProctorRoomConnectionData.class) .getBuilder(GetProctorRoomConnectionData.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(proctoringSettings.examId)) .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(proctoringSettings.examId))
.withQueryParam(SEBProctoringConnectionData.ATTR_ROOM_NAME, room.name) .withQueryParam(SEBProctoringConnection.ATTR_ROOM_NAME, room.name)
.withQueryParam(SEBProctoringConnectionData.ATTR_SUBJECT, Utils.encodeFormURL_UTF_8(room.subject)) .withQueryParam(SEBProctoringConnection.ATTR_SUBJECT, Utils.encodeFormURL_UTF_8(room.subject))
.call() .call()
.getOrThrow(); .getOrThrow();
@ -499,7 +499,7 @@ public class MonitoringClientConnection implements TemplateComposer {
.getProctoringGUIService(); .getProctoringGUIService();
if (!proctoringGUIService.hasRoom(roomName)) { if (!proctoringGUIService.hasRoom(roomName)) {
final SEBProctoringConnectionData proctoringConnectionData = proctoringGUIService final SEBProctoringConnection proctoringConnectionData = proctoringGUIService
.registerNewSingleProcotringRoom( .registerNewSingleProcotringRoom(
examId, examId,
roomName, roomName,

View file

@ -44,7 +44,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; 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.model.session.ClientConnection.ConnectionStatus;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
@ -445,7 +445,7 @@ public class MonitoringRunningExam implements TemplateComposer {
String activeAllRoomName = proctoringGUIService.getTownhallRoom(examId.modelId); String activeAllRoomName = proctoringGUIService.getTownhallRoom(examId.modelId);
if (activeAllRoomName == null) { if (activeAllRoomName == null) {
final SEBProctoringConnectionData proctoringConnectionData = proctoringGUIService final SEBProctoringConnection proctoringConnectionData = proctoringGUIService
.registerTownhallRoom( .registerTownhallRoom(
examId.modelId, examId.modelId,
this.pageService.getI18nSupport().getText(EXAM_ROOM_NAME)) this.pageService.getI18nSupport().getText(EXAM_ROOM_NAME))
@ -642,12 +642,12 @@ public class MonitoringRunningExam implements TemplateComposer {
final RemoteProctoringRoom room, final RemoteProctoringRoom room,
final PageAction action) { final PageAction action) {
final SEBProctoringConnectionData proctoringConnectionData = this.pageService final SEBProctoringConnection proctoringConnectionData = this.pageService
.getRestService() .getRestService()
.getBuilder(GetProctorRoomConnectionData.class) .getBuilder(GetProctorRoomConnectionData.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(proctoringSettings.examId)) .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(proctoringSettings.examId))
.withQueryParam(SEBProctoringConnectionData.ATTR_ROOM_NAME, room.name) .withQueryParam(SEBProctoringConnection.ATTR_ROOM_NAME, room.name)
.withQueryParam(SEBProctoringConnectionData.ATTR_SUBJECT, Utils.encodeFormURL_UTF_8(room.subject)) .withQueryParam(SEBProctoringConnection.ATTR_SUBJECT, Utils.encodeFormURL_UTF_8(room.subject))
.call() .call()
.getOrThrow(); .getOrThrow();

View file

@ -17,20 +17,20 @@ import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class ActivateTownhallRoom extends RestCall<SEBProctoringConnectionData> { public class ActivateTownhallRoom extends RestCall<SEBProctoringConnection> {
public ActivateTownhallRoom() { public ActivateTownhallRoom() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.UNDEFINED, CallType.UNDEFINED,
EntityType.EXAM_PROCTOR_DATA, EntityType.EXAM_PROCTOR_DATA,
new TypeReference<SEBProctoringConnectionData>() { new TypeReference<SEBProctoringConnection>() {
}), }),
HttpMethod.POST, HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -17,20 +17,20 @@ import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class GetProctorRoomConnectionData extends RestCall<SEBProctoringConnectionData> { public class GetProctorRoomConnectionData extends RestCall<SEBProctoringConnection> {
public GetProctorRoomConnectionData() { public GetProctorRoomConnectionData() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.GET_SINGLE, CallType.GET_SINGLE,
EntityType.EXAM_PROCTOR_DATA, EntityType.EXAM_PROCTOR_DATA,
new TypeReference<SEBProctoringConnectionData>() { new TypeReference<SEBProctoringConnection>() {
}), }),
HttpMethod.GET, HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -17,20 +17,20 @@ import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class SendJoinRemoteProctoringRoom extends RestCall<SEBProctoringConnectionData> { public class SendJoinRemoteProctoringRoom extends RestCall<SEBProctoringConnection> {
public SendJoinRemoteProctoringRoom() { public SendJoinRemoteProctoringRoom() {
super(new TypeKey<>( super(new TypeKey<>(
CallType.UNDEFINED, CallType.UNDEFINED,
EntityType.EXAM_PROCTOR_DATA, EntityType.EXAM_PROCTOR_DATA,
new TypeReference<SEBProctoringConnectionData>() { new TypeReference<SEBProctoringConnection>() {
}), }),
HttpMethod.POST, HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_FORM_URLENCODED,

View file

@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ActivateTownhallRoom; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ActivateTownhallRoom;
@ -82,7 +82,7 @@ public class ProctoringGUIService {
public static void setCurrentProctoringWindowData( public static void setCurrentProctoringWindowData(
final String examId, final String examId,
final SEBProctoringConnectionData data) { final SEBProctoringConnection data) {
RWT.getUISession().getHttpSession().setAttribute( RWT.getUISession().getHttpSession().setAttribute(
SESSION_ATTR_PROCTORING_DATA, SESSION_ATTR_PROCTORING_DATA,
@ -103,7 +103,7 @@ public class ProctoringGUIService {
.orElseGet(() -> null); .orElseGet(() -> null);
} }
public Result<SEBProctoringConnectionData> registerNewSingleProcotringRoom( public Result<SEBProctoringConnection> registerNewSingleProcotringRoom(
final String examId, final String examId,
final String roomName, final String roomName,
final String subject, final String subject,
@ -111,8 +111,8 @@ public class ProctoringGUIService {
return this.restService.getBuilder(SendJoinRemoteProctoringRoom.class) return this.restService.getBuilder(SendJoinRemoteProctoringRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, examId) .withURIVariable(API.PARAM_MODEL_ID, examId)
.withFormParam(SEBProctoringConnectionData.ATTR_ROOM_NAME, roomName) .withFormParam(SEBProctoringConnection.ATTR_ROOM_NAME, roomName)
.withFormParam(SEBProctoringConnectionData.ATTR_SUBJECT, subject) .withFormParam(SEBProctoringConnection.ATTR_SUBJECT, subject)
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken) .withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken)
.call() .call()
.map(connection -> { .map(connection -> {
@ -122,13 +122,13 @@ public class ProctoringGUIService {
}); });
} }
public Result<SEBProctoringConnectionData> registerTownhallRoom( public Result<SEBProctoringConnection> registerTownhallRoom(
final String examId, final String examId,
final String subject) { final String subject) {
return this.restService.getBuilder(ActivateTownhallRoom.class) return this.restService.getBuilder(ActivateTownhallRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, examId) .withURIVariable(API.PARAM_MODEL_ID, examId)
.withFormParam(SEBProctoringConnectionData.ATTR_SUBJECT, subject) .withFormParam(SEBProctoringConnection.ATTR_SUBJECT, subject)
.call() .call()
.map(connection -> { .map(connection -> {
this.rooms.put( this.rooms.put(
@ -139,7 +139,7 @@ public class ProctoringGUIService {
}); });
} }
public Result<SEBProctoringConnectionData> registerNewProcotringRoom( public Result<SEBProctoringConnection> registerNewProcotringRoom(
final String examId, final String examId,
final String roomName, final String roomName,
final String subject, final String subject,
@ -147,8 +147,8 @@ public class ProctoringGUIService {
return this.restService.getBuilder(SendJoinRemoteProctoringRoom.class) return this.restService.getBuilder(SendJoinRemoteProctoringRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, examId) .withURIVariable(API.PARAM_MODEL_ID, examId)
.withFormParam(SEBProctoringConnectionData.ATTR_ROOM_NAME, roomName) .withFormParam(SEBProctoringConnection.ATTR_ROOM_NAME, roomName)
.withFormParam(SEBProctoringConnectionData.ATTR_SUBJECT, subject) .withFormParam(SEBProctoringConnection.ATTR_SUBJECT, subject)
.withFormParam( .withFormParam(
API.EXAM_API_SEB_CONNECTION_TOKEN, API.EXAM_API_SEB_CONNECTION_TOKEN,
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR_CHAR)) StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR_CHAR))
@ -172,7 +172,7 @@ public class ProctoringGUIService {
} }
this.restService.getBuilder(SendJoinRemoteProctoringRoom.class) this.restService.getBuilder(SendJoinRemoteProctoringRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, examId) .withURIVariable(API.PARAM_MODEL_ID, examId)
.withFormParam(SEBProctoringConnectionData.ATTR_ROOM_NAME, room) .withFormParam(SEBProctoringConnection.ATTR_ROOM_NAME, room)
.withFormParam( .withFormParam(
API.EXAM_API_SEB_CONNECTION_TOKEN, API.EXAM_API_SEB_CONNECTION_TOKEN,
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR_CHAR)) StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR_CHAR))
@ -288,11 +288,11 @@ public class ProctoringGUIService {
public static class ProctoringWindowData { public static class ProctoringWindowData {
public final String examId; public final String examId;
public final SEBProctoringConnectionData connectionData; public final SEBProctoringConnection connectionData;
protected ProctoringWindowData( protected ProctoringWindowData(
final String examId, final String examId,
final SEBProctoringConnectionData connectionData) { final SEBProctoringConnection connectionData) {
this.examId = examId; this.examId = examId;
this.connectionData = connectionData; this.connectionData = connectionData;
} }

View file

@ -10,7 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
@ -33,36 +33,28 @@ public interface ExamProctoringService {
* @param roomName the name of the room * @param roomName the name of the room
* @param subject name of the room * @param subject name of the room
* @return SEBProctoringConnectionData that contains all connection data */ * @return SEBProctoringConnectionData that contains all connection data */
Result<SEBProctoringConnectionData> createProctorPublicRoomConnection( Result<SEBProctoringConnection> createProctorPublicRoomConnection(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final String roomName, final String roomName,
final String subject); final String subject);
Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData( Result<SEBProctoringConnection> getClientExamCollectingRoomConnection(
final ProctoringSettings proctoringSettings,
final String connectionToken);
Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final ClientConnection connection); final ClientConnection connection);
Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData( Result<SEBProctoringConnection> getClientExamCollectingRoomConnection(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final String connectionToken, final String connectionToken,
final String roomName, final String roomName,
final String subject); final String subject);
Result<SEBProctoringConnectionData> getClientRoomConnectionData( Result<SEBProctoringConnection> getClientRoomConnection(
final ProctoringSettings proctoringSettings,
final String connectionToken);
Result<SEBProctoringConnectionData> getClientRoomConnectionData(
final ProctoringSettings examProctoring, final ProctoringSettings examProctoring,
final String connectionToken, final String connectionToken,
final String roomName, final String roomName,
final String subject); final String subject);
Result<SEBProctoringConnectionData> createProctoringConnectionData( Result<SEBProctoringConnection> createProctoringConnection(
final ProctoringServerType proctoringServerType, final ProctoringServerType proctoringServerType,
final String connectionToken, final String connectionToken,
final String url, final String url,

View file

@ -25,7 +25,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@ -77,13 +77,13 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
} }
@Override @Override
public Result<SEBProctoringConnectionData> createProctorPublicRoomConnection( public Result<SEBProctoringConnection> createProctorPublicRoomConnection(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final String roomName, final String roomName,
final String subject) { final String subject) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
return createProctoringConnectionData( return createProctoringConnection(
proctoringSettings.serverType, proctoringSettings.serverType,
null, null,
proctoringSettings.serverURL, proctoringSettings.serverURL,
@ -100,19 +100,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
} }
@Override @Override
public Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData( public Result<SEBProctoringConnection> getClientExamCollectingRoomConnection(
final ProctoringSettings proctoringSettings,
final String connectionToken) {
return this.examSessionService
.getConnectionData(connectionToken)
.flatMap(connection -> getClientExamCollectingRoomConnectionData(
proctoringSettings,
connection.clientConnection));
}
@Override
public Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final ClientConnection connection) { final ClientConnection connection) {
@ -122,7 +110,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
.getRoomName(connection.getRemoteProctoringRoomId()) .getRoomName(connection.getRemoteProctoringRoomId())
.getOrThrow(); .getOrThrow();
return createProctoringConnectionData( return createProctoringConnection(
proctoringSettings.serverType, proctoringSettings.serverType,
null, null,
proctoringSettings.serverURL, proctoringSettings.serverURL,
@ -139,7 +127,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
} }
@Override @Override
public Result<SEBProctoringConnectionData> getClientExamCollectingRoomConnectionData( public Result<SEBProctoringConnection> getClientExamCollectingRoomConnection(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final String connectionToken, final String connectionToken,
final String roomName, final String roomName,
@ -150,7 +138,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
.getConnectionData(connectionToken) .getConnectionData(connectionToken)
.getOrThrow(); .getOrThrow();
return createProctoringConnectionData( return createProctoringConnection(
proctoringSettings.serverType, proctoringSettings.serverType,
null, null,
proctoringSettings.serverURL, proctoringSettings.serverURL,
@ -167,29 +155,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
} }
@Override @Override
public Result<SEBProctoringConnectionData> getClientRoomConnectionData( public Result<SEBProctoringConnection> getClientRoomConnection(
final ProctoringSettings proctoringSettings,
final String connectionToken) {
return Result.tryCatch(() -> this.examSessionService
.getConnectionData(connectionToken)
.getOrThrow()
).flatMap(clientConnection -> {
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
final String roomName = urlEncoder.encodeToString(
Utils.toByteArray(clientConnection.clientConnection.connectionToken));
return getClientRoomConnectionData(
proctoringSettings,
connectionToken,
roomName,
clientConnection.clientConnection.userSessionId);
});
}
@Override
public Result<SEBProctoringConnectionData> getClientRoomConnectionData(
final ProctoringSettings proctoringSettings, final ProctoringSettings proctoringSettings,
final String connectionToken, final String connectionToken,
final String roomName, final String roomName,
@ -202,7 +168,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
.getConnectionData(connectionToken) .getConnectionData(connectionToken)
.getOrThrow(); .getOrThrow();
return createProctoringConnectionData( return createProctoringConnection(
proctoringSettings.serverType, proctoringSettings.serverType,
connectionToken, connectionToken,
proctoringSettings.serverURL, proctoringSettings.serverURL,
@ -220,7 +186,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
} }
@Override @Override
public Result<SEBProctoringConnectionData> createProctoringConnectionData( public Result<SEBProctoringConnection> createProctoringConnection(
final ProctoringServerType proctoringServerType, final ProctoringServerType proctoringServerType,
final String connectionToken, final String connectionToken,
final String url, final String url,
@ -250,7 +216,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
host, host,
moderator); moderator);
return new SEBProctoringConnectionData( return new SEBProctoringConnection(
proctoringServerType, proctoringServerType,
connectionToken, connectionToken,
host, host,

View file

@ -20,7 +20,7 @@ import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
@ -196,9 +196,9 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
.getExamProctoring(examId) .getExamProctoring(examId)
.getOrThrow(); .getOrThrow();
final SEBProctoringConnectionData proctoringData = final SEBProctoringConnection proctoringData =
this.examAdminService.getExamProctoringService(proctoringSettings.serverType) this.examAdminService.getExamProctoringService(proctoringSettings.serverType)
.flatMap(s -> s.getClientExamCollectingRoomConnectionData( .flatMap(s -> s.getClientExamCollectingRoomConnection(
proctoringSettings, proctoringSettings,
connectionToken, connectionToken,
roomName, roomName,

View file

@ -9,6 +9,8 @@
package ch.ethz.seb.sebserver.webservice.weblayer.api; package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -31,13 +33,14 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom; import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService; import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
@ -108,14 +111,14 @@ public class ExamProctoringController {
method = RequestMethod.GET, method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE) produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public SEBProctoringConnectionData getProctorRoomData( public SEBProctoringConnection getProctorRoomData(
@RequestParam( @RequestParam(
name = API.PARAM_INSTITUTION_ID, name = API.PARAM_INSTITUTION_ID,
required = true, required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId, @PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
@RequestParam(name = SEBProctoringConnectionData.ATTR_ROOM_NAME, required = true) final String roomName, @RequestParam(name = SEBProctoringConnection.ATTR_ROOM_NAME, required = true) final String roomName,
@RequestParam(name = SEBProctoringConnectionData.ATTR_SUBJECT, required = false) final String subject) { @RequestParam(name = SEBProctoringConnection.ATTR_SUBJECT, required = false) final String subject) {
checkAccess(institutionId, examId); checkAccess(institutionId, examId);
@ -217,27 +220,12 @@ public class ExamProctoringController {
checkAccess(institutionId, examId); checkAccess(institutionId, examId);
final ProctoringSettings settings = this.examSessionService final ProctoringSettings proctoringSettings = this.examSessionService
.getRunningExam(examId) .getRunningExam(examId)
.flatMap(this.examAdminService::getExamProctoring) .flatMap(this.examAdminService::getExamProctoring)
.getOrThrow(); .getOrThrow();
final ExamProctoringService examProctoringService = this.examAdminService sendJoinInstructions(connectionTokens, proctoringSettings);
.getExamProctoringService(settings.serverType)
.getOrThrow();
Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
.stream()
.forEach(connectionToken -> {
examProctoringService
.getClientExamCollectingRoomConnectionData(
settings,
connectionToken)
.flatMap(data -> this.sendJoinInstruction(examId, connectionToken, data))
.onError(error -> log.error("Failed to send rejoin for: {} cause: {}",
connectionToken,
error.getMessage()));
});
} }
@RequestMapping( @RequestMapping(
@ -245,17 +233,17 @@ public class ExamProctoringController {
+ API.EXAM_PROCTORING_JOIN_ROOM_PATH_SEGMENT, + API.EXAM_PROCTORING_JOIN_ROOM_PATH_SEGMENT,
method = RequestMethod.POST, method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE) produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public SEBProctoringConnectionData sendJoinProctoringRoomToClients( public SEBProctoringConnection sendJoinProctoringRoomToClients(
@RequestParam( @RequestParam(
name = API.PARAM_INSTITUTION_ID, name = API.PARAM_INSTITUTION_ID,
required = true, required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId, @PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
@RequestParam( @RequestParam(
name = SEBProctoringConnectionData.ATTR_ROOM_NAME, name = SEBProctoringConnection.ATTR_ROOM_NAME,
required = true) final String roomName, required = true) final String roomName,
@RequestParam( @RequestParam(
name = SEBProctoringConnectionData.ATTR_SUBJECT, name = SEBProctoringConnection.ATTR_SUBJECT,
required = false) final String subject, required = false) final String subject,
@RequestParam( @RequestParam(
name = API.EXAM_API_SEB_CONNECTION_TOKEN, name = API.EXAM_API_SEB_CONNECTION_TOKEN,
@ -273,33 +261,24 @@ public class ExamProctoringController {
.getOrThrow(); .getOrThrow();
if (StringUtils.isNotBlank(connectionTokens)) { if (StringUtils.isNotBlank(connectionTokens)) {
final boolean single = connectionTokens.contains(Constants.LIST_SEPARATOR);
(single Arrays.asList(connectionTokens.split(Constants.LIST_SEPARATOR))
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
: Arrays.asList(connectionTokens))
.stream() .stream()
.forEach(connectionToken -> { .forEach(connectionToken -> {
final SEBProctoringConnectionData data = (single) final SEBProctoringConnection proctoringConnection =
? examProctoringService examProctoringService
.getClientRoomConnectionData(settings, connectionToken) .getClientRoomConnection(
.onError(error -> log.error(
"Failed to get client room connection data for {} cause: {}",
connectionToken,
error.getMessage()))
.get()
: examProctoringService
.getClientRoomConnectionData(
settings, settings,
connectionToken, connectionToken,
roomName, verifyRoomName(roomName, connectionToken),
(StringUtils.isNotBlank(subject)) ? subject : roomName) (StringUtils.isNotBlank(subject)) ? subject : roomName)
.onError(error -> log.error( .onError(error -> log.error(
"Failed to get client room connection data for {} cause: {}", "Failed to get client room connection data for {} cause: {}",
connectionToken, connectionToken,
error.getMessage())) error.getMessage()))
.get(); .get();
if (data != null) { if (proctoringConnection != null) {
sendJoinInstruction(examId, connectionToken, data) sendJoinInstruction(settings.examId, connectionToken, proctoringConnection)
.onError(error -> log.error( .onError(error -> log.error(
"Failed to send proctoring leave instruction to client: {} cause: {}", "Failed to send proctoring leave instruction to client: {} cause: {}",
connectionToken, connectionToken,
@ -315,6 +294,16 @@ public class ExamProctoringController {
.getOrThrow(); .getOrThrow();
} }
private String verifyRoomName(final String requestedRoomName, final String connectionToken) {
if (StringUtils.isNotBlank(requestedRoomName)) {
return requestedRoomName;
}
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
return urlEncoder.encodeToString(
Utils.toByteArray(connectionToken));
}
@RequestMapping( @RequestMapping(
path = API.MODEL_ID_VAR_PATH_SEGMENT path = API.MODEL_ID_VAR_PATH_SEGMENT
+ API.EXAM_PROCTORING_TOWNHALL_ROOM_DATA, + API.EXAM_PROCTORING_TOWNHALL_ROOM_DATA,
@ -338,14 +327,14 @@ public class ExamProctoringController {
+ API.EXAM_PROCTORING_ACTIVATE_TOWNHALL_ROOM, + API.EXAM_PROCTORING_ACTIVATE_TOWNHALL_ROOM,
method = RequestMethod.POST, method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE) produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public SEBProctoringConnectionData activateTownhall( public SEBProctoringConnection activateTownhall(
@RequestParam( @RequestParam(
name = API.PARAM_INSTITUTION_ID, name = API.PARAM_INSTITUTION_ID,
required = true, required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId, @PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
@RequestParam( @RequestParam(
name = SEBProctoringConnectionData.ATTR_SUBJECT, name = SEBProctoringConnection.ATTR_SUBJECT,
required = false) final String subject) { required = false) final String subject) {
checkAccess(institutionId, examId); checkAccess(institutionId, examId);
@ -371,8 +360,8 @@ public class ExamProctoringController {
.getOrThrow() .getOrThrow()
.stream() .stream()
.forEach(cc -> { .forEach(cc -> {
final SEBProctoringConnectionData data = examProctoringService final SEBProctoringConnection data = examProctoringService
.getClientRoomConnectionData( .getClientRoomConnection(
settings, settings,
cc.clientConnection.connectionToken, cc.clientConnection.connectionToken,
townhallRoom.name, townhallRoom.name,
@ -431,7 +420,7 @@ public class ExamProctoringController {
.stream() .stream()
.forEach(cc -> { .forEach(cc -> {
examProctoringService examProctoringService
.getClientExamCollectingRoomConnectionData( .getClientExamCollectingRoomConnection(
settings, settings,
cc.clientConnection) cc.clientConnection)
.flatMap(data -> this.sendJoinInstruction( .flatMap(data -> this.sendJoinInstruction(
@ -455,9 +444,25 @@ public class ExamProctoringController {
return; return;
} }
if (StringUtils.isNotBlank(connectionTokens)) { final boolean definedClients = StringUtils.isNotBlank(connectionTokens);
// we have defined connection tokens to send instructions to final boolean inTownhall = this.examProcotringRoomService.getTownhallRoomData(examId).hasValue();
final boolean roomSpecified = StringUtils.isNotBlank(roomName);
if (definedClients) {
sendBroadcastInstructionsToClients(examId, connectionTokens, attributes);
} else if (inTownhall) {
sendBroadcastInstructionToClientsInExam(examId, attributes);
} else if (roomSpecified) {
sendBroadcastInstructionToClientsInRoom(examId, roomName, attributes);
} else {
throw new RuntimeException("API attribute validation error: missing "
+ Domain.REMOTE_PROCTORING_ROOM.ATTR_ID + " and/or" +
API.EXAM_API_SEB_CONNECTION_TOKEN + " attribute");
}
}
private void sendBroadcastInstructionsToClients(final Long examId, final String connectionTokens,
final Map<String, String> attributes) {
final boolean single = connectionTokens.contains(Constants.LIST_SEPARATOR); final boolean single = connectionTokens.contains(Constants.LIST_SEPARATOR);
(single (single
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR)) ? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
@ -476,10 +481,11 @@ public class ExamProctoringController {
error)); error));
}); });
} else if (this.examProcotringRoomService.getTownhallRoomData(examId).hasValue()) { }
// we are in the town hall so all active connections are involved
this.examSessionService.getAllActiveConnectionData(examId) private void sendBroadcastInstructionToClientsInExam(final Long examId, final Map<String, String> attributes) {
this.examSessionService
.getAllActiveConnectionData(examId)
.getOrThrow() .getOrThrow()
.stream() .stream()
.forEach(connection -> { .forEach(connection -> {
@ -494,10 +500,15 @@ public class ExamProctoringController {
connection.clientConnection.connectionToken, connection.clientConnection.connectionToken,
error)); error));
}); });
} else if (StringUtils.isNotBlank(roomName)) { }
// we have a room name so all connection of this room are involved
this.examProcotringRoomService.getRoomConnections(examId, roomName) private void sendBroadcastInstructionToClientsInRoom(
final Long examId,
final String roomName,
final Map<String, String> attributes) {
this.examProcotringRoomService
.getRoomConnections(examId, roomName)
.getOrThrow() .getOrThrow()
.stream() .stream()
.filter(ExamSessionService.ACTIVE_CONNECTION_FILTER) .filter(ExamSessionService.ACTIVE_CONNECTION_FILTER)
@ -513,19 +524,48 @@ public class ExamProctoringController {
connection.connectionToken, connection.connectionToken,
error)); error));
}); });
} else {
throw new RuntimeException("API attribute validation error: missing "
+ Domain.REMOTE_PROCTORING_ROOM.ATTR_ID + " and/or" +
API.EXAM_API_SEB_CONNECTION_TOKEN + " attribute");
} }
private void sendJoinInstructions(
final String connectionTokens,
final ProctoringSettings proctoringSettings) {
final ExamProctoringService examProctoringService = this.examAdminService
.getExamProctoringService(proctoringSettings.serverType)
.getOrThrow();
Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
.stream()
.forEach(connectionToken -> {
sendJoinInstructionToClient(proctoringSettings, examProctoringService, connectionToken);
});
}
private void sendJoinInstructionToClient(
final ProctoringSettings proctoringSettings,
final ExamProctoringService examProctoringService,
final String connectionToken) {
this.examSessionService
.getConnectionData(connectionToken)
.flatMap(connection -> examProctoringService.getClientExamCollectingRoomConnection(
proctoringSettings,
connection.clientConnection))
.flatMap(data -> this.sendJoinInstruction(
proctoringSettings.examId,
connectionToken, data))
.onError(error -> log.error("Failed to send rejoin for: {} cause: {}",
connectionToken,
error.getMessage()));
} }
private Result<Void> sendJoinInstruction( private Result<Void> sendJoinInstruction(
final Long examId, final Long examId,
final String connectionToken, final String connectionToken,
final SEBProctoringConnectionData data) { final SEBProctoringConnection data) {
final Map<String, String> attributes = new HashMap<>(); final Map<String, String> attributes = new HashMap<>();
attributes.put( attributes.put(
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.SERVICE_TYPE, ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.SERVICE_TYPE,
ProctoringSettings.ProctoringServerType.JITSI_MEET.name()); ProctoringSettings.ProctoringServerType.JITSI_MEET.name());
@ -541,6 +581,7 @@ public class ExamProctoringController {
attributes.put( attributes.put(
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.JITSI_TOKEN, ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.JITSI_TOKEN,
data.accessToken); data.accessToken);
return this.sebInstructionService.registerInstruction( return this.sebInstructionService.registerInstruction(
examId, examId,
InstructionType.SEB_PROCTORING, InstructionType.SEB_PROCTORING,

View file

@ -18,7 +18,7 @@ import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringSettings.ProctoringServerType;
import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnectionData; import ch.ethz.seb.sebserver.gbl.model.exam.SEBProctoringConnection;
import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Cryptor;
public class ExamJITSIProctoringServiceTest { public class ExamJITSIProctoringServiceTest {
@ -63,7 +63,7 @@ public class ExamJITSIProctoringServiceTest {
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn("fbvgeghergrgrthrehreg123"); Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn("fbvgeghergrgrthrehreg123");
final ExamJITSIProctoringService examJITSIProctoringService = final ExamJITSIProctoringService examJITSIProctoringService =
new ExamJITSIProctoringService(null, null, null, cryptorMock); new ExamJITSIProctoringService(null, null, null, cryptorMock);
final SEBProctoringConnectionData data = examJITSIProctoringService.createProctoringConnectionData( final SEBProctoringConnection data = examJITSIProctoringService.createProctoringConnection(
ProctoringServerType.JITSI_MEET, ProctoringServerType.JITSI_MEET,
"connectionToken", "connectionToken",
"https://seb-jitsi.example.ch", "https://seb-jitsi.example.ch",