SEBSERV-139 Proctoring room join and leave API
This commit is contained in:
parent
9923e06029
commit
3ea936cf81
12 changed files with 252 additions and 51 deletions
|
@ -128,7 +128,9 @@ public final class API {
|
|||
public static final String EXAM_ADMINISTRATION_CHECK_RESTRICTION_PATH_SEGMENT = "/check-seb-restriction";
|
||||
public static final String EXAM_ADMINISTRATION_CHECK_IMPORTED_PATH_SEGMENT = "/check-imported";
|
||||
public static final String EXAM_ADMINISTRATION_SEB_RESTRICTION_CHAPTERS_PATH_SEGMENT = "/chapters";
|
||||
public static final String EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT = "/proctoring";
|
||||
public static final String PROCTOR_PATH_SEGMENT = "/proctoring";
|
||||
public static final String PROCTOR_JOIN_ROOM_PATH_SEGMENT = "/join";
|
||||
public static final String PROCTOR_LEAVE_ROOM_PATH_SEGMENT = "/leave";
|
||||
|
||||
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";
|
||||
|
||||
|
@ -166,9 +168,9 @@ public final class API {
|
|||
public static final String EXAM_MONITORING_ENDPOINT = "/monitoring";
|
||||
public static final String EXAM_MONITORING_INSTRUCTION_ENDPOINT = "/instruction";
|
||||
public static final String EXAM_MONITORING_DISABLE_CONNECTION_ENDPOINT = "/disable-connection";
|
||||
public static final String EXAM_MONITORING_STATE_FILTER = "hidden-states";
|
||||
public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
|
||||
"/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
|
||||
public static final String EXAM_MONITORING_STATE_FILTER = "hidden-states";
|
||||
|
||||
public static final String SEB_CLIENT_CONNECTION_ENDPOINT = "/seb-client-connection";
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@ public final class ClientInstruction {
|
|||
SEB_PROCTORING
|
||||
}
|
||||
|
||||
public enum ProctoringInstructionMethod {
|
||||
JOIN,
|
||||
LEAVE
|
||||
}
|
||||
|
||||
public interface SEB_INSTRUCTION_ATTRIBUTES {
|
||||
public interface SEB_PROCTORING {
|
||||
public static final String SERVICE_TYPE = "service-type";
|
||||
|
|
|
@ -54,7 +54,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicator
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetProctoringSettings;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionData;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorURLForClient;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorDataForSEBClient;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.session.ClientConnectionDetails;
|
||||
import ch.ethz.seb.sebserver.gui.service.session.InstructionProcessor;
|
||||
|
@ -296,7 +296,7 @@ public class MonitoringClientConnection implements TemplateComposer {
|
|||
|
||||
private PageAction openProctorScreen(final PageAction action, final String connectionToken) {
|
||||
final SEBClientProctoringConnectionData proctoringConnectionData =
|
||||
this.pageService.getRestService().getBuilder(GetProctorURLForClient.class)
|
||||
this.pageService.getRestService().getBuilder(GetProctorDataForSEBClient.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId)
|
||||
.withURIVariable(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionToken)
|
||||
.call()
|
||||
|
|
|
@ -21,7 +21,7 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
|||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ProcotringViewRules implements ValueChangeRule {
|
||||
public class ProctoringViewRules implements ValueChangeRule {
|
||||
|
||||
public static final String KEY_ENABLE_AI = "proctoringAIEnable";
|
||||
public static final String KEY_ENABLE_JITSI = "jitsiMeetEnable";
|
|
@ -36,7 +36,7 @@ public class GetProctoringSettings extends RestCall<ProctoringSettings> {
|
|||
MediaType.APPLICATION_JSON_UTF8,
|
||||
API.EXAM_ADMINISTRATION_ENDPOINT
|
||||
+ API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT);
|
||||
+ API.PROCTOR_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class SaveProctoringSettings extends RestCall<Exam> {
|
|||
MediaType.APPLICATION_JSON_UTF8,
|
||||
API.EXAM_ADMINISTRATION_ENDPOINT
|
||||
+ API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT);
|
||||
+ API.PROCTOR_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
|||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetProctorURLForClient extends RestCall<SEBClientProctoringConnectionData> {
|
||||
public class GetProctorDataForSEBClient extends RestCall<SEBClientProctoringConnectionData> {
|
||||
|
||||
public GetProctorURLForClient() {
|
||||
public GetProctorDataForSEBClient() {
|
||||
super(new TypeKey<>(
|
||||
CallType.GET_SINGLE,
|
||||
EntityType.EXAM_PROCTOR_DATA,
|
||||
|
@ -34,9 +34,9 @@ public class GetProctorURLForClient extends RestCall<SEBClientProctoringConnecti
|
|||
}),
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.EXAM_ADMINISTRATION_ENDPOINT
|
||||
API.EXAM_MONITORING_ENDPOINT
|
||||
+ API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT
|
||||
+ API.PROCTOR_PATH_SEGMENT
|
||||
+ API.EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT);
|
||||
}
|
||||
|
|
@ -30,4 +30,9 @@ public interface ExamProctoringService {
|
|||
ClientConnection clientConnection,
|
||||
boolean server);
|
||||
|
||||
Result<SEBClientProctoringConnectionData> createProcotringDataForRoom(
|
||||
final ProctoringSettings examProctoring,
|
||||
final String roomName,
|
||||
final boolean server);
|
||||
|
||||
}
|
||||
|
|
|
@ -96,19 +96,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
|||
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
if (examProctoring.examId == null) {
|
||||
throw new IllegalStateException("Missing exam identifier from ExamProctoring data");
|
||||
}
|
||||
|
||||
long expTime = System.currentTimeMillis() + Constants.DAY_IN_MILLIS;
|
||||
if (this.examSessionService.isExamRunning(examProctoring.examId)) {
|
||||
final Exam exam = this.examSessionService.getRunningExam(examProctoring.examId)
|
||||
.getOrThrow();
|
||||
if (exam.endTime != null) {
|
||||
expTime = exam.endTime.getMillis();
|
||||
}
|
||||
}
|
||||
|
||||
final long expTime = forExam(examProctoring);
|
||||
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
|
||||
final String roomName = urlEncoder.encodeToString(
|
||||
Utils.toByteArray(clientConnection.connectionToken));
|
||||
|
@ -127,6 +115,29 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<SEBClientProctoringConnectionData> createProcotringDataForRoom(
|
||||
final ProctoringSettings examProctoring,
|
||||
final String roomName,
|
||||
final boolean server) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
final long expTime = forExam(examProctoring);
|
||||
|
||||
return createProctoringConnectionData(
|
||||
examProctoring.serverURL,
|
||||
examProctoring.appKey,
|
||||
examProctoring.getAppSecret(),
|
||||
this.authorizationService.getUserService().getCurrentUser().getUsername(),
|
||||
(server) ? "seb-server" : "seb-client",
|
||||
roomName,
|
||||
roomName,
|
||||
expTime)
|
||||
.getOrThrow();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public Result<SEBClientProctoringConnectionData> createProctoringConnectionData(
|
||||
final String url,
|
||||
final String appKey,
|
||||
|
@ -224,4 +235,20 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
private long forExam(final ProctoringSettings examProctoring) {
|
||||
if (examProctoring.examId == null) {
|
||||
throw new IllegalStateException("Missing exam identifier from ExamProctoring data");
|
||||
}
|
||||
|
||||
long expTime = System.currentTimeMillis() + Constants.DAY_IN_MILLIS;
|
||||
if (this.examSessionService.isExamRunning(examProctoring.examId)) {
|
||||
final Exam exam = this.examSessionService.getRunningExam(examProctoring.examId)
|
||||
.getOrThrow();
|
||||
if (exam.endTime != null) {
|
||||
expTime = exam.endTime.getMillis();
|
||||
}
|
||||
}
|
||||
return expTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
|
|||
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.QuizData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.SEBClientProctoringConnectionData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.Features;
|
||||
|
@ -384,7 +383,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
|||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT,
|
||||
+ API.PROCTOR_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ProctoringSettings getExamProctoring(
|
||||
|
@ -403,7 +402,7 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
|||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT,
|
||||
+ API.PROCTOR_PATH_SEGMENT,
|
||||
method = RequestMethod.POST,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public Exam saveExamProctoring(
|
||||
|
@ -425,30 +424,6 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> {
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.EXAM_ADMINISTRATION_PROCTOR_PATH_SEGMENT
|
||||
+ API.EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public SEBClientProctoringConnectionData getExamProctoringURL(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
||||
@PathVariable(name = API.EXAM_API_SEB_CONNECTION_TOKEN) final String connectionToken) {
|
||||
|
||||
checkReadPrivilege(institutionId);
|
||||
return this.entityDAO.byPK(examId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(this.examAdminService::getExamProctoring)
|
||||
.flatMap(proc -> this.examAdminService
|
||||
.getExamProctoringService(proc.serverType)
|
||||
.flatMap(s -> s.createProctoringConnectionData(proc, connectionToken, true)))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
// **** Proctoring
|
||||
// ****************************************************************************
|
||||
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -39,16 +42,22 @@ import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
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.SEBClientProctoringConnectionData;
|
||||
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.ClientInstruction;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamProctoringService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBInstructionService;
|
||||
|
@ -62,16 +71,19 @@ public class ExamMonitoringController {
|
|||
|
||||
private final SEBClientConnectionService sebClientConnectionService;
|
||||
private final ExamSessionService examSessionService;
|
||||
private final ExamAdminService examAdminService;
|
||||
private final SEBInstructionService sebInstructionService;
|
||||
private final AuthorizationService authorization;
|
||||
private final PaginationService paginationService;
|
||||
|
||||
public ExamMonitoringController(
|
||||
final ExamAdminService examAdminService,
|
||||
final SEBClientConnectionService sebClientConnectionService,
|
||||
final SEBInstructionService sebInstructionService,
|
||||
final AuthorizationService authorization,
|
||||
final PaginationService paginationService) {
|
||||
|
||||
this.examAdminService = examAdminService;
|
||||
this.sebClientConnectionService = sebClientConnectionService;
|
||||
this.examSessionService = sebClientConnectionService.getExamSessionService();
|
||||
this.sebInstructionService = sebInstructionService;
|
||||
|
@ -269,6 +281,127 @@ public class ExamMonitoringController {
|
|||
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.PROCTOR_PATH_SEGMENT
|
||||
+ API.EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public SEBClientProctoringConnectionData getClientSingleRoomProctoringData(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
||||
@PathVariable(name = API.EXAM_API_SEB_CONNECTION_TOKEN) final String connectionToken) {
|
||||
|
||||
this.authorization.check(
|
||||
PrivilegeType.READ,
|
||||
EntityType.EXAM,
|
||||
institutionId);
|
||||
|
||||
return this.examSessionService.getRunningExam(examId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(this.examAdminService::getExamProctoring)
|
||||
.flatMap(proc -> this.examAdminService
|
||||
.getExamProctoringService(proc.serverType)
|
||||
.flatMap(s -> s.createProctoringConnectionData(proc, connectionToken, true)))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.PROCTOR_PATH_SEGMENT
|
||||
+ API.PROCTOR_JOIN_ROOM_PATH_SEGMENT,
|
||||
method = RequestMethod.POST,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public SEBClientProctoringConnectionData joinProctoringRoom(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
||||
@RequestParam(
|
||||
name = SEBClientProctoringConnectionData.ATTR_ROOM_NAME,
|
||||
required = true) final String roomName,
|
||||
@RequestParam(
|
||||
name = API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||
required = true) final String connectionTokens) {
|
||||
|
||||
this.authorization.check(
|
||||
PrivilegeType.READ,
|
||||
EntityType.EXAM,
|
||||
institutionId);
|
||||
|
||||
final ProctoringSettings settings = this.examSessionService
|
||||
.getRunningExam(examId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(this.examAdminService::getExamProctoring)
|
||||
.getOrThrow();
|
||||
|
||||
final SEBClientProctoringConnectionData result = this.examAdminService
|
||||
.getExamProctoringService(settings.serverType)
|
||||
.flatMap(s -> s.createProcotringDataForRoom(settings, roomName, false))
|
||||
.getOrThrow();
|
||||
|
||||
if (StringUtils.isNotBlank(connectionTokens)) {
|
||||
(connectionTokens.contains(Constants.LIST_SEPARATOR)
|
||||
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
|
||||
: Arrays.asList(connectionTokens)).stream()
|
||||
.forEach(connectionToken -> sendJoinInstruction(examId, connectionToken, result)
|
||||
.onError(error -> log.error(
|
||||
"Failed to send proctoring leave instruction to client: {} ",
|
||||
connectionToken, error)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||
+ API.PROCTOR_PATH_SEGMENT
|
||||
+ API.PROCTOR_LEAVE_ROOM_PATH_SEGMENT,
|
||||
method = RequestMethod.POST,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public void leaveProctoringRoom(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
||||
@RequestParam(
|
||||
name = SEBClientProctoringConnectionData.ATTR_ROOM_NAME,
|
||||
required = true) final String roomName,
|
||||
@RequestParam(
|
||||
name = API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||
required = true) final String connectionTokens) {
|
||||
|
||||
this.authorization.check(
|
||||
PrivilegeType.READ,
|
||||
EntityType.EXAM,
|
||||
institutionId);
|
||||
|
||||
final ProctoringSettings settings = this.examSessionService
|
||||
.getRunningExam(examId)
|
||||
.flatMap(this.authorization::checkRead)
|
||||
.flatMap(this.examAdminService::getExamProctoring)
|
||||
.getOrThrow();
|
||||
|
||||
final ExamProctoringService examProctoringService = this.examAdminService
|
||||
.getExamProctoringService(settings.serverType)
|
||||
.getOrThrow();
|
||||
|
||||
(connectionTokens.contains(Constants.LIST_SEPARATOR)
|
||||
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
|
||||
: Arrays.asList(connectionTokens)).stream()
|
||||
.forEach(connectionToken -> examProctoringService
|
||||
.createProctoringConnectionData(settings, connectionToken, false)
|
||||
.flatMap(data -> sendLeaveInstruction(examId, connectionToken, data))
|
||||
.onError(error -> log.error(
|
||||
"Failed to send proctoring leave instruction to client: {} ",
|
||||
connectionToken, error)));
|
||||
}
|
||||
|
||||
private boolean hasRunningExamPrivilege(final Long examId, final Long institution) {
|
||||
return hasRunningExamPrivilege(
|
||||
this.examSessionService.getRunningExam(examId).getOr(null),
|
||||
|
@ -284,4 +417,57 @@ public class ExamMonitoringController {
|
|||
return exam.institutionId.equals(institution) && exam.isOwner(userId);
|
||||
}
|
||||
|
||||
private Result<Void> sendJoinInstruction(
|
||||
final Long examId,
|
||||
final String connectionToken,
|
||||
final SEBClientProctoringConnectionData data) {
|
||||
|
||||
return sendProctorInstruction(
|
||||
examId,
|
||||
connectionToken,
|
||||
data,
|
||||
ClientInstruction.ProctoringInstructionMethod.JOIN.name());
|
||||
}
|
||||
|
||||
private Result<Void> sendLeaveInstruction(
|
||||
final Long examId,
|
||||
final String connectionToken,
|
||||
final SEBClientProctoringConnectionData data) {
|
||||
|
||||
return sendProctorInstruction(
|
||||
examId,
|
||||
connectionToken,
|
||||
data,
|
||||
ClientInstruction.ProctoringInstructionMethod.LEAVE.name());
|
||||
}
|
||||
|
||||
private Result<Void> sendProctorInstruction(
|
||||
final Long examId,
|
||||
final String connectionToken,
|
||||
final SEBClientProctoringConnectionData data,
|
||||
final String method) {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put(
|
||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.SERVICE_TYPE,
|
||||
ProctoringSettings.ServerType.JITSI_MEET.name());
|
||||
attributes.put(
|
||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.METHOD,
|
||||
method);
|
||||
attributes.put(
|
||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.JITSI_URL,
|
||||
data.serverURL);
|
||||
attributes.put(
|
||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.JITSI_ROOM,
|
||||
data.roomName);
|
||||
attributes.put(
|
||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_PROCTORING.JITSI_TOKEN,
|
||||
data.accessToken);
|
||||
return this.sebInstructionService.registerInstruction(
|
||||
examId,
|
||||
InstructionType.SEB_PROCTORING,
|
||||
attributes,
|
||||
connectionToken,
|
||||
true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
server.address=localhost
|
||||
server.port=8080
|
||||
|
||||
sebserver.gui.http.external.scheme=http
|
||||
sebserver.gui.entrypoint=/gui
|
||||
sebserver.gui.webservice.protocol=http
|
||||
sebserver.gui.webservice.address=localhost
|
||||
|
|
Loading…
Add table
Reference in a new issue