fixed proctoring room issues
This commit is contained in:
parent
daebd9b5f7
commit
5b9b336886
9 changed files with 241 additions and 117 deletions
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gbl;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.eclipse.swt.graphics.RGB;
|
import org.eclipse.swt.graphics.RGB;
|
||||||
|
import org.eclipse.swt.graphics.RGBA;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
@ -124,6 +125,7 @@ public final class Constants {
|
||||||
|
|
||||||
public static final RGB WHITE_RGB = new RGB(255, 255, 255);
|
public static final RGB WHITE_RGB = new RGB(255, 255, 255);
|
||||||
public static final RGB BLACK_RGB = new RGB(0, 0, 0);
|
public static final RGB BLACK_RGB = new RGB(0, 0, 0);
|
||||||
|
public static final RGBA GREY_DISABLED = new RGBA(150, 150, 150, 50);
|
||||||
|
|
||||||
public static final String IMPORTED_PASSWORD_MARKER = "_IMPORTED_PASSWORD";
|
public static final String IMPORTED_PASSWORD_MARKER = "_IMPORTED_PASSWORD";
|
||||||
|
|
||||||
|
|
|
@ -286,28 +286,30 @@ public class MonitoringClientConnection implements TemplateComposer {
|
||||||
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) &&
|
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) &&
|
||||||
connectionData.clientConnection.status == ConnectionStatus.ACTIVE);
|
connectionData.clientConnection.status == ConnectionStatus.ACTIVE);
|
||||||
|
|
||||||
final ProctoringSettings procotringSettings = restService
|
// TODO if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) {
|
||||||
.getBuilder(GetProctoringSettings.class)
|
if (connectionData.clientConnection.status != ConnectionStatus.DISABLED) {
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
|
final ProctoringSettings procotringSettings = restService
|
||||||
.call()
|
.getBuilder(GetProctoringSettings.class)
|
||||||
.onError(error -> log.error("Failed to get ProctoringSettings", error))
|
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
|
||||||
.getOr(null);
|
.call()
|
||||||
|
.onError(error -> log.error("Failed to get ProctoringSettings", error))
|
||||||
|
.getOr(null);
|
||||||
|
|
||||||
if (procotringSettings != null && procotringSettings.enableProctoring) {
|
if (procotringSettings != null && procotringSettings.enableProctoring) {
|
||||||
actionBuilder
|
actionBuilder
|
||||||
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_PROCTORING)
|
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_PROCTORING)
|
||||||
.withEntityKey(parentEntityKey)
|
.withEntityKey(parentEntityKey)
|
||||||
.withExec(action -> this.openSingleProctorScreen(action, connectionData))
|
.withExec(action -> this.openSingleProctorScreen(action, connectionData))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publish()
|
.publish()
|
||||||
|
|
||||||
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_EXAM_ROOM_PROCTORING)
|
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_EXAM_ROOM_PROCTORING)
|
||||||
.withEntityKey(parentEntityKey)
|
.withEntityKey(parentEntityKey)
|
||||||
.withExec(action -> this.openExamCollectionProctorScreen(action, connectionData))
|
.withExec(action -> this.openExamCollectionProctorScreen(action, connectionData))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publish();
|
.publish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction openExamCollectionProctorScreen(
|
private PageAction openExamCollectionProctorScreen(
|
||||||
|
|
|
@ -20,9 +20,12 @@ import java.util.function.Function;
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
|
import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.graphics.Image;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
import org.eclipse.swt.widgets.Tree;
|
import org.eclipse.swt.widgets.Tree;
|
||||||
import org.eclipse.swt.widgets.TreeItem;
|
import org.eclipse.swt.widgets.TreeItem;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -31,6 +34,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
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.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
@ -49,6 +53,7 @@ import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.GuiServiceInfo;
|
import ch.ethz.seb.sebserver.gui.GuiServiceInfo;
|
||||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||||
|
import ch.ethz.seb.sebserver.gui.content.action.ActionPane;
|
||||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
@ -361,13 +366,13 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
room.subject,
|
room.subject,
|
||||||
room.roomSize,
|
room.roomSize,
|
||||||
proctoringSettings.collectingRoomSize)));
|
proctoringSettings.collectingRoomSize)));
|
||||||
|
processProctorRoomActionActivation(treeItem, room, pageContext);
|
||||||
} else {
|
} else {
|
||||||
// create new action
|
// create new action
|
||||||
final PageAction action =
|
final PageAction action =
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_VIEW_PROCTOR_ROOM)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_VIEW_PROCTOR_ROOM)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(a -> showExamProctoringRoom(proctoringSettings, room, a))
|
.withExec(a -> showExamProctoringRoom(proctoringSettings, room, rooms, a))
|
||||||
.withNameAttributes(
|
.withNameAttributes(
|
||||||
room.subject,
|
room.subject,
|
||||||
room.roomSize,
|
room.roomSize,
|
||||||
|
@ -376,42 +381,89 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
this.pageService.publishAction(action, treeItem -> rooms.put(room, treeItem));
|
this.pageService.publishAction(action, treeItem -> rooms.put(room, treeItem));
|
||||||
|
addRoomConnectionsPopupListener(entityKey, pageContext, rooms);
|
||||||
// check and add show connections in room action adaptation
|
rooms.entrySet().stream()
|
||||||
if (!rooms.isEmpty()) {
|
.filter(entry -> entry.getKey().equals(room))
|
||||||
final TreeItem treeItem = rooms.values().iterator().next();
|
.findFirst()
|
||||||
final Tree tree = treeItem.getParent();
|
.ifPresent(entry -> processProctorRoomActionActivation(
|
||||||
if (tree.getData(SHOW_CONNECTION_ACTION_APPLIED) == null) {
|
entry.getValue(),
|
||||||
tree.addListener(SWT.Selection, event -> {
|
room,
|
||||||
final TreeItem item = (TreeItem) event.item;
|
pageContext));
|
||||||
treeItem.getParent().deselectAll();
|
|
||||||
if (event.button == 3) {
|
|
||||||
rooms.entrySet()
|
|
||||||
.stream()
|
|
||||||
.filter(e -> e.getValue().equals(item))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresent(e -> {
|
|
||||||
final PageContext pc = pageContext.copy()
|
|
||||||
.clearAttributes()
|
|
||||||
.withEntityKey(new EntityKey(e.getKey().getName(),
|
|
||||||
EntityType.REMOTE_PROCTORING_ROOM))
|
|
||||||
.withParentEntityKey(entityKey);
|
|
||||||
this.proctorRoomConnectionsPopup.show(pc, e.getKey().getSubject());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tree.setData(SHOW_CONNECTION_ACTION_APPLIED, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processProctorRoomActionActivation(
|
||||||
|
final TreeItem treeItem,
|
||||||
|
final RemoteProctoringRoom room,
|
||||||
|
final PageContext pageContext) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Display display = pageContext.getRoot().getDisplay();
|
||||||
|
final PageAction action = (PageAction) treeItem.getData(ActionPane.ACTION_EVENT_CALL_KEY);
|
||||||
|
final Image image = room.roomSize > 0
|
||||||
|
? action.definition.icon.getImage(display)
|
||||||
|
: action.definition.icon.getGreyedImage(display);
|
||||||
|
treeItem.setImage(image);
|
||||||
|
treeItem.setForeground(room.roomSize > 0 ? null : new Color(display, Constants.GREY_DISABLED));
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to set Proctor-Room-Activation: ", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRoomConnectionsPopupListener(
|
||||||
|
final EntityKey entityKey,
|
||||||
|
final PageContext pageContext,
|
||||||
|
final Map<RemoteProctoringRoom, TreeItem> rooms) {
|
||||||
|
|
||||||
|
if (!rooms.isEmpty()) {
|
||||||
|
final TreeItem treeItem = rooms.values().iterator().next();
|
||||||
|
final Tree tree = treeItem.getParent();
|
||||||
|
if (tree.getData(SHOW_CONNECTION_ACTION_APPLIED) == null) {
|
||||||
|
tree.addListener(SWT.Selection, event -> {
|
||||||
|
final TreeItem item = (TreeItem) event.item;
|
||||||
|
item.getParent().deselectAll();
|
||||||
|
if (event.button == 3) {
|
||||||
|
rooms.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(e -> e.getValue().equals(item))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(e -> {
|
||||||
|
if (e.getKey().roomSize > 0) {
|
||||||
|
final PageContext pc = pageContext.copy()
|
||||||
|
.clearAttributes()
|
||||||
|
.withEntityKey(new EntityKey(e.getKey().getName(),
|
||||||
|
EntityType.REMOTE_PROCTORING_ROOM))
|
||||||
|
.withParentEntityKey(entityKey);
|
||||||
|
this.proctorRoomConnectionsPopup.show(pc, e.getKey().getSubject());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tree.setData(SHOW_CONNECTION_ACTION_APPLIED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getActualRoomSize(final RemoteProctoringRoom room, final Map<RemoteProctoringRoom, TreeItem> rooms) {
|
||||||
|
return rooms.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getKey().equals(room))
|
||||||
|
.findFirst()
|
||||||
|
.map(entry -> entry.getKey().roomSize)
|
||||||
|
.orElseGet(() -> 1);
|
||||||
|
}
|
||||||
|
|
||||||
private PageAction showExamProctoringRoom(
|
private PageAction showExamProctoringRoom(
|
||||||
final ProctoringSettings proctoringSettings,
|
final ProctoringSettings proctoringSettings,
|
||||||
final RemoteProctoringRoom room,
|
final RemoteProctoringRoom room,
|
||||||
|
final Map<RemoteProctoringRoom, TreeItem> rooms,
|
||||||
final PageAction action) {
|
final PageAction action) {
|
||||||
|
|
||||||
|
final int actualRoomSize = getActualRoomSize(room, rooms);
|
||||||
|
if (actualRoomSize <= 0) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
final SEBProctoringConnectionData proctoringConnectionData = this.pageService
|
final SEBProctoringConnectionData proctoringConnectionData = this.pageService
|
||||||
.getRestService()
|
.getRestService()
|
||||||
.getBuilder(GetProctorRoomConnectionData.class)
|
.getBuilder(GetProctorRoomConnectionData.class)
|
||||||
|
|
|
@ -47,7 +47,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
@Component
|
@Component
|
||||||
public class ActionPane implements TemplateComposer {
|
public class ActionPane implements TemplateComposer {
|
||||||
|
|
||||||
private static final String ACTION_EVENT_CALL_KEY = "ACTION_EVENT_CALL";
|
public static final String ACTION_EVENT_CALL_KEY = "ACTION_EVENT_CALL";
|
||||||
private static final LocTextKey TITLE_KEY = new LocTextKey("sebserver.actionpane.title");
|
private static final LocTextKey TITLE_KEY = new LocTextKey("sebserver.actionpane.title");
|
||||||
|
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
|
@ -226,7 +226,7 @@ public class ActionPane implements TemplateComposer {
|
||||||
final Tree actions = this.widgetFactory.treeLocalized(
|
final Tree actions = this.widgetFactory.treeLocalized(
|
||||||
composite,
|
composite,
|
||||||
SWT.SINGLE | SWT.FULL_SELECTION | SWT.NO_SCROLL);
|
SWT.SINGLE | SWT.FULL_SELECTION | SWT.NO_SCROLL);
|
||||||
actions.setData(RWT.CUSTOM_VARIANT, "actions");
|
actions.setData(RWT.CUSTOM_VARIANT, CustomVariant.ACTIONS.key);
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||||
actions.setLayoutData(gridData);
|
actions.setLayoutData(gridData);
|
||||||
final Template template = new Template();
|
final Template template = new Template();
|
||||||
|
|
|
@ -99,7 +99,6 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
browser.setLayoutData(gridData);
|
browser.setLayoutData(gridData);
|
||||||
browser.setUrl(url);
|
browser.setUrl(url);
|
||||||
//browser.layout();
|
|
||||||
browser.setBackground(new Color(parent.getDisplay(), 100, 100, 100));
|
browser.setBackground(new Color(parent.getDisplay(), 100, 100, 100));
|
||||||
|
|
||||||
final Composite footer = new Composite(content, SWT.NONE | SWT.NO_SCROLL);
|
final Composite footer = new Composite(content, SWT.NONE | SWT.NO_SCROLL);
|
||||||
|
@ -118,12 +117,14 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
.closeRoom(proctoringWindowData.connectionData.roomName));
|
.closeRoom(proctoringWindowData.connectionData.roomName));
|
||||||
|
|
||||||
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
||||||
|
final String connectionTokens = getConnectionTokens(proctoringWindowData);
|
||||||
|
|
||||||
final Button broadcastAudioAction = widgetFactory.buttonLocalized(footer, BROADCAST_AUDIO_ON_TEXT_KEY);
|
final Button broadcastAudioAction = widgetFactory.buttonLocalized(footer, BROADCAST_AUDIO_ON_TEXT_KEY);
|
||||||
broadcastAudioAction.setLayoutData(new RowData(150, 30));
|
broadcastAudioAction.setLayoutData(new RowData(150, 30));
|
||||||
broadcastAudioAction.addListener(SWT.Selection, event -> toggleBroadcastAudio(
|
broadcastAudioAction.addListener(SWT.Selection, event -> toggleBroadcastAudio(
|
||||||
proctoringWindowData.examId,
|
proctoringWindowData.examId,
|
||||||
proctoringWindowData.connectionData.roomName,
|
proctoringWindowData.connectionData.roomName,
|
||||||
|
connectionTokens,
|
||||||
broadcastAudioAction));
|
broadcastAudioAction));
|
||||||
broadcastAudioAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
broadcastAudioAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
broadcastVideoAction.addListener(SWT.Selection, event -> toggleBroadcastVideo(
|
broadcastVideoAction.addListener(SWT.Selection, event -> toggleBroadcastVideo(
|
||||||
proctoringWindowData.examId,
|
proctoringWindowData.examId,
|
||||||
proctoringWindowData.connectionData.roomName,
|
proctoringWindowData.connectionData.roomName,
|
||||||
|
connectionTokens,
|
||||||
broadcastVideoAction,
|
broadcastVideoAction,
|
||||||
broadcastAudioAction));
|
broadcastAudioAction));
|
||||||
broadcastVideoAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
broadcastVideoAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
||||||
|
@ -141,12 +143,26 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
chatAction.addListener(SWT.Selection, event -> toggleChat(
|
chatAction.addListener(SWT.Selection, event -> toggleChat(
|
||||||
proctoringWindowData.examId,
|
proctoringWindowData.examId,
|
||||||
proctoringWindowData.connectionData.roomName,
|
proctoringWindowData.connectionData.roomName,
|
||||||
|
connectionTokens,
|
||||||
chatAction));
|
chatAction));
|
||||||
chatAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
chatAction.setData(BroadcastActionState.KEY_NAME, broadcastActionState);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleBroadcastAudio(final String examId, final String roomName, final Button broadcastAction) {
|
private String getConnectionTokens(final ProctoringWindowData proctoringWindowData) {
|
||||||
|
final String connectionTokens = this.pageService
|
||||||
|
.getCurrentUser()
|
||||||
|
.getProctoringGUIService()
|
||||||
|
.getRoomConnectionTokens(proctoringWindowData.connectionData.roomName);
|
||||||
|
return connectionTokens == null ? "" : connectionTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleBroadcastAudio(
|
||||||
|
final String examId,
|
||||||
|
final String roomName,
|
||||||
|
final String connectionTokens,
|
||||||
|
final Button broadcastAction) {
|
||||||
|
|
||||||
final BroadcastActionState state =
|
final BroadcastActionState state =
|
||||||
(BroadcastActionState) broadcastAction.getData(BroadcastActionState.KEY_NAME);
|
(BroadcastActionState) broadcastAction.getData(BroadcastActionState.KEY_NAME);
|
||||||
if (state.audio) {
|
if (state.audio) {
|
||||||
|
@ -154,6 +170,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
@ -164,6 +181,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
@ -176,6 +194,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
private void toggleBroadcastVideo(
|
private void toggleBroadcastVideo(
|
||||||
final String examId,
|
final String examId,
|
||||||
final String roomName,
|
final String roomName,
|
||||||
|
final String connectionTokens,
|
||||||
final Button videoAction,
|
final Button videoAction,
|
||||||
final Button audioAction) {
|
final Button audioAction) {
|
||||||
final BroadcastActionState state =
|
final BroadcastActionState state =
|
||||||
|
@ -187,6 +206,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
@ -201,6 +221,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
@ -214,7 +235,12 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
state.audio = state.video;
|
state.audio = state.video;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleChat(final String examId, final String roomName, final Button broadcastAction) {
|
private void toggleChat(
|
||||||
|
final String examId,
|
||||||
|
final String roomName,
|
||||||
|
final String connectionTokens,
|
||||||
|
final Button broadcastAction) {
|
||||||
|
|
||||||
final BroadcastActionState state =
|
final BroadcastActionState state =
|
||||||
(BroadcastActionState) broadcastAction.getData(BroadcastActionState.KEY_NAME);
|
(BroadcastActionState) broadcastAction.getData(BroadcastActionState.KEY_NAME);
|
||||||
if (state.chat) {
|
if (state.chat) {
|
||||||
|
@ -222,6 +248,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOffInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_ALLOW_CHAT,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_ALLOW_CHAT,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
@ -232,6 +259,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
this.pageService.getRestService().getBuilder(SendProctoringBroadcastOnInstruction.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
.withURIVariable(API.PARAM_MODEL_ID, examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomName)
|
||||||
|
.withFormParam(API.EXAM_API_SEB_CONNECTION_TOKEN, connectionTokens)
|
||||||
.withFormParam(
|
.withFormParam(
|
||||||
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_ALLOW_CHAT,
|
ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_ALLOW_CHAT,
|
||||||
Constants.TRUE_STRING)
|
Constants.TRUE_STRING)
|
||||||
|
|
|
@ -61,13 +61,24 @@ public class ProctoringGUIService {
|
||||||
return this.rooms.keySet();
|
return this.rooms.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRoomConnectionTokens(final String roomName) {
|
||||||
|
if (this.rooms.containsKey(roomName)) {
|
||||||
|
return StringUtils.join(this.rooms.get(roomName).connections, Constants.COMMA);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static ProctoringWindowData getCurrentProctoringWindowData() {
|
public static ProctoringWindowData getCurrentProctoringWindowData() {
|
||||||
return (ProctoringWindowData) RWT.getUISession()
|
return (ProctoringWindowData) RWT.getUISession()
|
||||||
.getHttpSession()
|
.getHttpSession()
|
||||||
.getAttribute(SESSION_ATTR_PROCTORING_DATA);
|
.getAttribute(SESSION_ATTR_PROCTORING_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCurrentProctoringWindowData(final String examId, final SEBProctoringConnectionData data) {
|
public static void setCurrentProctoringWindowData(
|
||||||
|
final String examId,
|
||||||
|
final SEBProctoringConnectionData data) {
|
||||||
|
|
||||||
RWT.getUISession().getHttpSession().setAttribute(
|
RWT.getUISession().getHttpSession().setAttribute(
|
||||||
SESSION_ATTR_PROCTORING_DATA,
|
SESSION_ATTR_PROCTORING_DATA,
|
||||||
new ProctoringWindowData(examId, data));
|
new ProctoringWindowData(examId, data));
|
||||||
|
@ -220,8 +231,9 @@ public class ProctoringGUIService {
|
||||||
public final String examId;
|
public final String examId;
|
||||||
public final SEBProctoringConnectionData connectionData;
|
public final SEBProctoringConnectionData connectionData;
|
||||||
|
|
||||||
protected ProctoringWindowData(final String examId, final SEBProctoringConnectionData connectionData) {
|
protected ProctoringWindowData(
|
||||||
super();
|
final String examId,
|
||||||
|
final SEBProctoringConnectionData connectionData) {
|
||||||
this.examId = examId;
|
this.examId = examId;
|
||||||
this.connectionData = connectionData;
|
this.connectionData = connectionData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,6 +174,8 @@ public class WidgetFactory {
|
||||||
TEXT_ACTION("action"),
|
TEXT_ACTION("action"),
|
||||||
TEXT_READONLY("readonlyText"),
|
TEXT_READONLY("readonlyText"),
|
||||||
|
|
||||||
|
ACTIONS("actions"),
|
||||||
|
|
||||||
FORM_CENTER("form-center"),
|
FORM_CENTER("form-center"),
|
||||||
SELECTION("selection"),
|
SELECTION("selection"),
|
||||||
SELECTED("selected"),
|
SELECTED("selected"),
|
||||||
|
|
|
@ -72,36 +72,6 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public Result<SEBProctoringConnectionData> createProctorPrivateRoomConnection(
|
|
||||||
// final ProctoringSettings proctoringSettings,
|
|
||||||
// final String connectionToken) {
|
|
||||||
//
|
|
||||||
// return Result.tryCatch(() -> {
|
|
||||||
//
|
|
||||||
// final ClientConnectionData clientConnection = this.examSessionService.getConnectionData(connectionToken)
|
|
||||||
// .getOrThrow();
|
|
||||||
//
|
|
||||||
// final long expTime = forExam(proctoringSettings);
|
|
||||||
// final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
|
|
||||||
// final String roomName = urlEncoder.encodeToString(
|
|
||||||
// Utils.toByteArray(clientConnection.clientConnection.connectionToken));
|
|
||||||
//
|
|
||||||
// return createProctoringConnectionData(
|
|
||||||
// proctoringSettings.serverType,
|
|
||||||
// connectionToken,
|
|
||||||
// proctoringSettings.serverURL,
|
|
||||||
// proctoringSettings.appKey,
|
|
||||||
// proctoringSettings.getAppSecret(),
|
|
||||||
// this.authorizationService.getUserService().getCurrentUser().getUsername(),
|
|
||||||
// "seb-server",
|
|
||||||
// roomName,
|
|
||||||
// clientConnection.clientConnection.userSessionId,
|
|
||||||
// expTime)
|
|
||||||
// .getOrThrow();
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<SEBProctoringConnectionData> createProctorPublicRoomConnection(
|
public Result<SEBProctoringConnectionData> createProctorPublicRoomConnection(
|
||||||
final ProctoringSettings proctoringSettings,
|
final ProctoringSettings proctoringSettings,
|
||||||
|
|
|
@ -388,7 +388,10 @@ public class ExamMonitoringController {
|
||||||
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId,
|
||||||
@RequestParam(
|
@RequestParam(
|
||||||
name = Domain.REMOTE_PROCTORING_ROOM.ATTR_ID,
|
name = Domain.REMOTE_PROCTORING_ROOM.ATTR_ID,
|
||||||
required = true) final String roomName,
|
required = false) final String roomName,
|
||||||
|
@RequestParam(
|
||||||
|
name = API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||||
|
required = false) final String connectionTokens,
|
||||||
@RequestParam(
|
@RequestParam(
|
||||||
name = ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
name = ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
required = false) final Boolean sendReceiveAudio,
|
required = false) final Boolean sendReceiveAudio,
|
||||||
|
@ -429,21 +432,46 @@ public class ExamMonitoringController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.examProcotringRoomService.getRoomConnections(examId, roomName)
|
if (StringUtils.isNotBlank(connectionTokens)) {
|
||||||
.getOrThrow()
|
final boolean single = connectionTokens.contains(Constants.LIST_SEPARATOR);
|
||||||
.stream()
|
(single
|
||||||
.forEach(connection -> {
|
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
|
||||||
this.sebInstructionService.registerInstruction(
|
: Arrays.asList(connectionTokens))
|
||||||
examId,
|
.stream()
|
||||||
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
.forEach(connectionToken -> {
|
||||||
attributes,
|
this.sebInstructionService.registerInstruction(
|
||||||
connection.connectionToken,
|
examId,
|
||||||
true)
|
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
||||||
.onError(error -> log.error(
|
attributes,
|
||||||
"Failed to register reconfiguring instruction for connection: {}",
|
connectionToken,
|
||||||
connection.connectionToken,
|
true)
|
||||||
error));
|
.onError(error -> log.error(
|
||||||
});
|
"Failed to register reconfiguring instruction for connection: {}",
|
||||||
|
connectionToken,
|
||||||
|
error));
|
||||||
|
|
||||||
|
});
|
||||||
|
} else if (StringUtils.isNotBlank(roomName)) {
|
||||||
|
this.examProcotringRoomService.getRoomConnections(examId, roomName)
|
||||||
|
.getOrThrow()
|
||||||
|
.stream()
|
||||||
|
.forEach(connection -> {
|
||||||
|
this.sebInstructionService.registerInstruction(
|
||||||
|
examId,
|
||||||
|
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
||||||
|
attributes,
|
||||||
|
connection.connectionToken,
|
||||||
|
true)
|
||||||
|
.onError(error -> log.error(
|
||||||
|
"Failed to register reconfiguring instruction for connection: {}",
|
||||||
|
connection.connectionToken,
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
|
@ -461,6 +489,9 @@ public class ExamMonitoringController {
|
||||||
@RequestParam(
|
@RequestParam(
|
||||||
name = Domain.REMOTE_PROCTORING_ROOM.ATTR_ID,
|
name = Domain.REMOTE_PROCTORING_ROOM.ATTR_ID,
|
||||||
required = true) final String roomName,
|
required = true) final String roomName,
|
||||||
|
@RequestParam(
|
||||||
|
name = API.EXAM_API_SEB_CONNECTION_TOKEN,
|
||||||
|
required = true) final String connectionTokens,
|
||||||
@RequestParam(
|
@RequestParam(
|
||||||
name = ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
name = ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_RECONFIGURE_SETTINGS.JITSI_RECEIVE_AUDIO,
|
||||||
required = false) final Boolean sendReceiveAudio,
|
required = false) final Boolean sendReceiveAudio,
|
||||||
|
@ -501,21 +532,46 @@ public class ExamMonitoringController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.examProcotringRoomService.getRoomConnections(examId, roomName)
|
if (StringUtils.isNotBlank(connectionTokens)) {
|
||||||
.getOrThrow()
|
final boolean single = connectionTokens.contains(Constants.LIST_SEPARATOR);
|
||||||
.stream()
|
(single
|
||||||
.forEach(connection -> {
|
? Arrays.asList(StringUtils.split(connectionTokens, Constants.LIST_SEPARATOR))
|
||||||
this.sebInstructionService.registerInstruction(
|
: Arrays.asList(connectionTokens))
|
||||||
examId,
|
.stream()
|
||||||
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
.forEach(connectionToken -> {
|
||||||
attributes,
|
this.sebInstructionService.registerInstruction(
|
||||||
connection.connectionToken,
|
examId,
|
||||||
true)
|
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
||||||
.onError(error -> log.error(
|
attributes,
|
||||||
"Failed to register reconfiguring instruction for connection: {}",
|
connectionToken,
|
||||||
connection.connectionToken,
|
true)
|
||||||
error));
|
.onError(error -> log.error(
|
||||||
});
|
"Failed to register reconfiguring instruction for connection: {}",
|
||||||
|
connectionToken,
|
||||||
|
error));
|
||||||
|
});
|
||||||
|
} else if (StringUtils.isNotBlank(roomName)) {
|
||||||
|
|
||||||
|
this.examProcotringRoomService.getRoomConnections(examId, roomName)
|
||||||
|
.getOrThrow()
|
||||||
|
.stream()
|
||||||
|
.forEach(connection -> {
|
||||||
|
this.sebInstructionService.registerInstruction(
|
||||||
|
examId,
|
||||||
|
InstructionType.SEB_RECONFIGURE_SETTINGS,
|
||||||
|
attributes,
|
||||||
|
connection.connectionToken,
|
||||||
|
true)
|
||||||
|
.onError(error -> log.error(
|
||||||
|
"Failed to register reconfiguring instruction for connection: {}",
|
||||||
|
connection.connectionToken,
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
|
|
Loading…
Add table
Reference in a new issue