SEBSERV-139 single used town-hall and code-cleanup
This commit is contained in:
parent
9d5ed34ec6
commit
8470e3b160
10 changed files with 290 additions and 136 deletions
|
@ -186,6 +186,7 @@ public final class API {
|
||||||
public static final String EXAM_PROCTORING_ACTIVATE_TOWNHALL_ROOM = "activate-towhall-room";
|
public static final String EXAM_PROCTORING_ACTIVATE_TOWNHALL_ROOM = "activate-towhall-room";
|
||||||
public static final String EXAM_PROCTORING_DEACTIVATE_TOWNHALL_ROOM = "deactivate-towhall-room";
|
public static final String EXAM_PROCTORING_DEACTIVATE_TOWNHALL_ROOM = "deactivate-towhall-room";
|
||||||
public static final String EXAM_PROCTORING_TOWNHALL_ROOM_DATA = "towhall-room-data";
|
public static final String EXAM_PROCTORING_TOWNHALL_ROOM_DATA = "towhall-room-data";
|
||||||
|
public static final String EXAM_PROCTORING_TOWNHALL_ROOM_AVAILABLE = "towhall-available";
|
||||||
|
|
||||||
public static final String SEB_CLIENT_CONNECTION_ENDPOINT = "/seb-client-connection";
|
public static final String SEB_CLIENT_CONNECTION_ENDPOINT = "/seb-client-connection";
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
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;
|
||||||
|
@ -78,6 +79,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClient
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProcotringRooms;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProcotringRooms;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorRoomConnectionData;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorRoomConnectionData;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetTownhallRoom;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetTownhallRoom;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.IsTownhallRoomAvailable;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||||
import ch.ethz.seb.sebserver.gui.service.session.ClientConnectionTable;
|
import ch.ethz.seb.sebserver.gui.service.session.ClientConnectionTable;
|
||||||
import ch.ethz.seb.sebserver.gui.service.session.InstructionProcessor;
|
import ch.ethz.seb.sebserver.gui.service.session.InstructionProcessor;
|
||||||
|
@ -123,6 +125,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
private final ServerPushService serverPushService;
|
private final ServerPushService serverPushService;
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
|
private final RestService restService;
|
||||||
private final ResourceService resourceService;
|
private final ResourceService resourceService;
|
||||||
private final AsyncRunner asyncRunner;
|
private final AsyncRunner asyncRunner;
|
||||||
private final InstructionProcessor instructionProcessor;
|
private final InstructionProcessor instructionProcessor;
|
||||||
|
@ -147,6 +150,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
this.serverPushService = serverPushService;
|
this.serverPushService = serverPushService;
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
|
this.restService = pageService.getRestService();
|
||||||
this.resourceService = pageService.getResourceService();
|
this.resourceService = pageService.getResourceService();
|
||||||
this.asyncRunner = asyncRunner;
|
this.asyncRunner = asyncRunner;
|
||||||
this.instructionProcessor = instructionProcessor;
|
this.instructionProcessor = instructionProcessor;
|
||||||
|
@ -214,13 +218,14 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
this.serverPushService.runServerPush(
|
this.serverPushService.runServerPush(
|
||||||
new ServerPushContext(
|
new ServerPushContext(
|
||||||
content, Utils.truePredicate(),
|
content,
|
||||||
|
Utils.truePredicate(),
|
||||||
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
||||||
this.pollInterval,
|
this.pollInterval,
|
||||||
context -> clientTable.updateValues(),
|
context -> clientTable.updateValues(),
|
||||||
updateTableGUI(clientTable));
|
updateTableGUI(clientTable));
|
||||||
|
|
||||||
final BooleanSupplier privilege = () -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER);
|
final BooleanSupplier isExamSupporter = () -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER);
|
||||||
|
|
||||||
actionBuilder
|
actionBuilder
|
||||||
|
|
||||||
|
@ -242,20 +247,20 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
return copyOfPageAction;
|
return copyOfPageAction;
|
||||||
})
|
})
|
||||||
.publishIf(privilege, false)
|
.publishIf(isExamSupporter, false)
|
||||||
|
|
||||||
.newAction(ActionDefinition.MONITOR_EXAM_QUIT_ALL)
|
.newAction(ActionDefinition.MONITOR_EXAM_QUIT_ALL)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withConfirm(() -> CONFIRM_QUIT_ALL)
|
.withConfirm(() -> CONFIRM_QUIT_ALL)
|
||||||
.withExec(action -> this.quitSEBClients(action, clientTable, true))
|
.withExec(action -> this.quitSEBClients(action, clientTable, true))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(privilege)
|
.publishIf(isExamSupporter)
|
||||||
|
|
||||||
.newAction(ActionDefinition.MONITORING_EXAM_SEARCH_CONNECTIONS)
|
.newAction(ActionDefinition.MONITORING_EXAM_SEARCH_CONNECTIONS)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
.withExec(this::openSearchPopup)
|
.withExec(this::openSearchPopup)
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(privilege)
|
.publishIf(isExamSupporter)
|
||||||
|
|
||||||
.newAction(ActionDefinition.MONITOR_EXAM_QUIT_SELECTED)
|
.newAction(ActionDefinition.MONITOR_EXAM_QUIT_SELECTED)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
|
@ -265,7 +270,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
action -> this.quitSEBClients(action, clientTable, false),
|
action -> this.quitSEBClients(action, clientTable, false),
|
||||||
EMPTY_ACTIVE_SELECTION_TEXT_KEY)
|
EMPTY_ACTIVE_SELECTION_TEXT_KEY)
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(privilege, false)
|
.publishIf(isExamSupporter, false)
|
||||||
|
|
||||||
.newAction(ActionDefinition.MONITOR_EXAM_DISABLE_SELECTED_CONNECTION)
|
.newAction(ActionDefinition.MONITOR_EXAM_DISABLE_SELECTED_CONNECTION)
|
||||||
.withEntityKey(entityKey)
|
.withEntityKey(entityKey)
|
||||||
|
@ -275,31 +280,111 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
action -> this.disableSEBClients(action, clientTable, false),
|
action -> this.disableSEBClients(action, clientTable, false),
|
||||||
EMPTY_SELECTION_TEXT_KEY)
|
EMPTY_SELECTION_TEXT_KEY)
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(privilege, false);
|
.publishIf(isExamSupporter, false);
|
||||||
|
|
||||||
if (privilege.getAsBoolean()) {
|
if (isExamSupporter.getAsBoolean()) {
|
||||||
|
addFilterActions(actionBuilder, clientTable, isExamSupporter);
|
||||||
|
addProctoringActions(
|
||||||
|
currentUser.getProctoringGUIService(),
|
||||||
|
pageContext,
|
||||||
|
content,
|
||||||
|
actionBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (clientTable.isStatusHidden(ConnectionStatus.CLOSED)) {
|
private void addProctoringActions(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
|
final ProctoringGUIService proctoringGUIService,
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
final PageContext pageContext,
|
||||||
|
final Composite parent,
|
||||||
|
final PageActionBuilder actionBuilder) {
|
||||||
|
|
||||||
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
|
final ProctoringSettings proctoringSettings = this.restService
|
||||||
|
.getBuilder(GetProctoringSettings.class)
|
||||||
|
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||||
|
.call()
|
||||||
|
.getOr(null);
|
||||||
|
|
||||||
|
if (proctoringSettings != null && proctoringSettings.enableProctoring) {
|
||||||
|
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
|
||||||
|
.withEntityKey(entityKey)
|
||||||
|
.withExec(action -> this.toggleTownhallRoom(proctoringGUIService, action))
|
||||||
|
.noEventPropagation()
|
||||||
|
.publish();
|
||||||
|
|
||||||
|
if (isTownhallRoomActive(entityKey.modelId)) {
|
||||||
|
this.pageService.firePageEvent(
|
||||||
|
new ActionActivationEvent(
|
||||||
|
true,
|
||||||
|
new Tuple<>(
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
||||||
|
pageContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> availableRooms = new HashMap<>();
|
||||||
|
updateRoomActions(
|
||||||
|
pageContext,
|
||||||
|
availableRooms,
|
||||||
|
actionBuilder,
|
||||||
|
proctoringSettings,
|
||||||
|
proctoringGUIService);
|
||||||
|
this.serverPushService.runServerPush(
|
||||||
|
new ServerPushContext(
|
||||||
|
parent,
|
||||||
|
Utils.truePredicate(),
|
||||||
|
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
||||||
|
this.proctoringRoomUpdateInterval,
|
||||||
|
context -> updateRoomActions(
|
||||||
|
pageContext,
|
||||||
|
availableRooms,
|
||||||
|
actionBuilder,
|
||||||
|
proctoringSettings,
|
||||||
|
proctoringGUIService));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFilterActions(
|
||||||
|
final PageActionBuilder actionBuilder,
|
||||||
|
final ClientConnectionTable clientTable,
|
||||||
|
final BooleanSupplier isExamSupporter) {
|
||||||
|
|
||||||
|
addClosedFilterAction(actionBuilder, clientTable);
|
||||||
|
addRequestedFilterAction(actionBuilder, clientTable);
|
||||||
|
addDisabledFilterAction(actionBuilder, clientTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisabledFilterAction(
|
||||||
|
final PageActionBuilder actionBuilder,
|
||||||
|
final ClientConnectionTable clientTable) {
|
||||||
|
|
||||||
|
if (clientTable.isStatusHidden(ConnectionStatus.DISABLED)) {
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
||||||
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.withSwitchAction(
|
.withSwitchAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
} else {
|
} else {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.withSwitchAction(
|
.withSwitchAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRequestedFilterAction(
|
||||||
|
final PageActionBuilder actionBuilder,
|
||||||
|
final ClientConnectionTable clientTable) {
|
||||||
|
|
||||||
if (clientTable.isStatusHidden(ConnectionStatus.CONNECTION_REQUESTED)) {
|
if (clientTable.isStatusHidden(ConnectionStatus.CONNECTION_REQUESTED)) {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
|
||||||
|
@ -324,85 +409,42 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (clientTable.isStatusHidden(ConnectionStatus.DISABLED)) {
|
private void addClosedFilterAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
final PageActionBuilder actionBuilder,
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
final ClientConnectionTable clientTable) {
|
||||||
|
|
||||||
|
if (clientTable.isStatusHidden(ConnectionStatus.CLOSED)) {
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
|
||||||
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.withSwitchAction(
|
.withSwitchAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
} else {
|
} else {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.withSwitchAction(
|
.withSwitchAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
final ProctoringSettings proctoringSettings = restService
|
|
||||||
.getBuilder(GetProctoringSettings.class)
|
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
|
||||||
.call()
|
|
||||||
.getOr(null);
|
|
||||||
|
|
||||||
if (proctoringSettings != null && proctoringSettings.enableProctoring) {
|
|
||||||
|
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
|
|
||||||
.withEntityKey(entityKey)
|
|
||||||
.withExec(this::toggleTownhallRoom)
|
|
||||||
.noEventPropagation()
|
|
||||||
.publish();
|
|
||||||
|
|
||||||
if (isTownhallRoomActive(entityKey.modelId)) {
|
|
||||||
this.pageService.firePageEvent(
|
|
||||||
new ActionActivationEvent(
|
|
||||||
true,
|
|
||||||
new Tuple<>(
|
|
||||||
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
|
||||||
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
|
||||||
pageContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> availableRooms = new HashMap<>();
|
|
||||||
updateRoomActions(
|
|
||||||
entityKey,
|
|
||||||
pageContext,
|
|
||||||
availableRooms,
|
|
||||||
actionBuilder,
|
|
||||||
proctoringSettings);
|
|
||||||
this.serverPushService.runServerPush(
|
|
||||||
new ServerPushContext(
|
|
||||||
content,
|
|
||||||
Utils.truePredicate(),
|
|
||||||
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
|
||||||
this.proctoringRoomUpdateInterval,
|
|
||||||
context -> updateRoomActions(
|
|
||||||
entityKey,
|
|
||||||
pageContext,
|
|
||||||
availableRooms,
|
|
||||||
actionBuilder,
|
|
||||||
proctoringSettings));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTownhallRoomActive(final String examModelId) {
|
private boolean isTownhallRoomActive(final String examModelId) {
|
||||||
final RemoteProctoringRoom townhall = this.pageService.getRestService()
|
return !BooleanUtils.toBoolean(this.pageService
|
||||||
.getBuilder(GetTownhallRoom.class)
|
.getRestService()
|
||||||
|
.getBuilder(IsTownhallRoomAvailable.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, examModelId)
|
.withURIVariable(API.PARAM_MODEL_ID, examModelId)
|
||||||
.call()
|
.call()
|
||||||
.getOr(null);
|
.getOr(Constants.FALSE_STRING));
|
||||||
|
|
||||||
return townhall != null && townhall.id != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction openSearchPopup(final PageAction action) {
|
private PageAction openSearchPopup(final PageAction action) {
|
||||||
|
@ -410,9 +452,12 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction toggleTownhallRoom(final PageAction action) {
|
private PageAction toggleTownhallRoom(
|
||||||
|
final ProctoringGUIService proctoringGUIService,
|
||||||
|
final PageAction action) {
|
||||||
|
|
||||||
if (isTownhallRoomActive(action.getEntityKey().modelId)) {
|
if (isTownhallRoomActive(action.getEntityKey().modelId)) {
|
||||||
closeTownhallRoom(action);
|
closeTownhallRoom(proctoringGUIService, action);
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(
|
new ActionActivationEvent(
|
||||||
true,
|
true,
|
||||||
|
@ -422,7 +467,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
action.pageContext());
|
action.pageContext());
|
||||||
return action;
|
return action;
|
||||||
} else {
|
} else {
|
||||||
openTownhallRoom(action);
|
openTownhallRoom(proctoringGUIService, action);
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(
|
new ActionActivationEvent(
|
||||||
true,
|
true,
|
||||||
|
@ -434,14 +479,12 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction openTownhallRoom(final PageAction action) {
|
private PageAction openTownhallRoom(
|
||||||
|
final ProctoringGUIService proctoringGUIService,
|
||||||
|
final PageAction action) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final EntityKey examId = action.getEntityKey();
|
final EntityKey examId = action.getEntityKey();
|
||||||
|
|
||||||
final ProctoringGUIService proctoringGUIService = this.pageService
|
|
||||||
.getCurrentUser()
|
|
||||||
.getProctoringGUIService();
|
|
||||||
|
|
||||||
String activeAllRoomName = proctoringGUIService.getTownhallRoom(examId.modelId);
|
String activeAllRoomName = proctoringGUIService.getTownhallRoom(examId.modelId);
|
||||||
|
|
||||||
if (activeAllRoomName == null) {
|
if (activeAllRoomName == null) {
|
||||||
|
@ -476,7 +519,10 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageAction closeTownhallRoom(final PageAction action) {
|
private PageAction closeTownhallRoom(
|
||||||
|
final ProctoringGUIService proctoringGUIService,
|
||||||
|
final PageAction action) {
|
||||||
|
|
||||||
final String examId = action.getEntityKey().modelId;
|
final String examId = action.getEntityKey().modelId;
|
||||||
final RemoteProctoringRoom townhall = this.pageService.getRestService()
|
final RemoteProctoringRoom townhall = this.pageService.getRestService()
|
||||||
.getBuilder(GetTownhallRoom.class)
|
.getBuilder(GetTownhallRoom.class)
|
||||||
|
@ -492,19 +538,22 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ProctoringGUIService proctoringGUIService = this.pageService
|
|
||||||
.getCurrentUser()
|
|
||||||
.getProctoringGUIService();
|
|
||||||
|
|
||||||
proctoringGUIService.closeRoom(townhall.name);
|
proctoringGUIService.closeRoom(townhall.name);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to close procotring townhall room for exam: {}", examId);
|
log.error("Failed to close proctoring townhall room for exam: {}", examId);
|
||||||
}
|
}
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTownhallButton(final EntityKey entityKey, final PageContext pageContext) {
|
private void updateTownhallButton(
|
||||||
|
final ProctoringGUIService proctoringGUIService,
|
||||||
|
final PageContext pageContext) {
|
||||||
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
|
|
||||||
if (isTownhallRoomActive(entityKey.modelId)) {
|
if (isTownhallRoomActive(entityKey.modelId)) {
|
||||||
|
final boolean townhallRoomFromThisUser = proctoringGUIService
|
||||||
|
.getTownhallRoom(entityKey.modelId) != null;
|
||||||
|
if (townhallRoomFromThisUser) {
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(
|
new ActionActivationEvent(
|
||||||
true,
|
true,
|
||||||
|
@ -512,25 +561,36 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
|
||||||
pageContext);
|
pageContext);
|
||||||
|
} else {
|
||||||
|
this.pageService.firePageEvent(
|
||||||
|
new ActionActivationEvent(
|
||||||
|
false,
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
||||||
|
pageContext);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.pageService.firePageEvent(
|
this.pageService.firePageEvent(
|
||||||
new ActionActivationEvent(
|
new ActionActivationEvent(
|
||||||
true,
|
true,
|
||||||
new Tuple<>(
|
new Tuple<>(
|
||||||
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)),
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM),
|
||||||
|
ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
|
||||||
|
ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM),
|
||||||
pageContext);
|
pageContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRoomActions(
|
private void updateRoomActions(
|
||||||
final EntityKey entityKey,
|
|
||||||
final PageContext pageContext,
|
final PageContext pageContext,
|
||||||
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> rooms,
|
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> rooms,
|
||||||
final PageActionBuilder actionBuilder,
|
final PageActionBuilder actionBuilder,
|
||||||
final ProctoringSettings proctoringSettings) {
|
final ProctoringSettings proctoringSettings,
|
||||||
|
final ProctoringGUIService proctoringGUIService) {
|
||||||
|
|
||||||
updateTownhallButton(entityKey, pageContext);
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
|
updateTownhallButton(proctoringGUIService, pageContext);
|
||||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||||
this.pageService.getRestService().getBuilder(GetProcotringRooms.class)
|
this.pageService.getRestService().getBuilder(GetProcotringRooms.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||||
|
@ -571,7 +631,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
this.pageService.publishAction(
|
this.pageService.publishAction(
|
||||||
action,
|
action,
|
||||||
_treeItem -> rooms.put(room.name, new Pair<>(room, _treeItem)));
|
_treeItem -> rooms.put(room.name, new Pair<>(room, _treeItem)));
|
||||||
addRoomConnectionsPopupListener(entityKey, pageContext, rooms);
|
addRoomConnectionsPopupListener(pageContext, rooms);
|
||||||
processProctorRoomActionActivation(rooms.get(room.name).b, room, pageContext);
|
processProctorRoomActionActivation(rooms.get(room.name).b, room, pageContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -596,11 +656,11 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRoomConnectionsPopupListener(
|
private void addRoomConnectionsPopupListener(
|
||||||
final EntityKey entityKey,
|
|
||||||
final PageContext pageContext,
|
final PageContext pageContext,
|
||||||
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> rooms) {
|
final Map<String, Pair<RemoteProctoringRoom, TreeItem>> rooms) {
|
||||||
|
|
||||||
if (!rooms.isEmpty()) {
|
if (!rooms.isEmpty()) {
|
||||||
|
final EntityKey entityKey = pageContext.getEntityKey();
|
||||||
final TreeItem treeItem = rooms.values().iterator().next().b;
|
final TreeItem treeItem = rooms.values().iterator().next().b;
|
||||||
final Tree tree = treeItem.getParent();
|
final Tree tree = treeItem.getParent();
|
||||||
if (tree.getData(SHOW_CONNECTION_ACTION_APPLIED) == null) {
|
if (tree.getData(SHOW_CONNECTION_ACTION_APPLIED) == null) {
|
||||||
|
|
|
@ -80,17 +80,18 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
public void compose(final PageContext pageContext) {
|
public void compose(final PageContext pageContext) {
|
||||||
|
|
||||||
final ProctoringWindowData proctoringWindowData = ProctoringGUIService.getCurrentProctoringWindowData();
|
final ProctoringWindowData proctoringWindowData = ProctoringGUIService.getCurrentProctoringWindowData();
|
||||||
|
|
||||||
final Composite parent = pageContext.getParent();
|
final Composite parent = pageContext.getParent();
|
||||||
|
|
||||||
final Composite content = new Composite(parent, SWT.NONE | SWT.NO_SCROLL);
|
final Composite content = new Composite(parent, SWT.NONE | SWT.NO_SCROLL);
|
||||||
final GridLayout gridLayout = new GridLayout();
|
final GridLayout gridLayout = new GridLayout();
|
||||||
|
final ProctoringGUIService proctoringGUIService = this.pageService
|
||||||
|
.getCurrentUser()
|
||||||
|
.getProctoringGUIService();
|
||||||
|
|
||||||
content.setLayout(gridLayout);
|
content.setLayout(gridLayout);
|
||||||
final GridData headerCell = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData headerCell = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
content.setLayoutData(headerCell);
|
content.setLayoutData(headerCell);
|
||||||
|
|
||||||
parent.addListener(SWT.Dispose, event -> closeRoom(proctoringWindowData));
|
parent.addListener(SWT.Dispose, event -> closeRoom(proctoringGUIService, proctoringWindowData));
|
||||||
|
|
||||||
final String url = this.guiServiceInfo
|
final String url = this.guiServiceInfo
|
||||||
.getExternalServerURIBuilder()
|
.getExternalServerURIBuilder()
|
||||||
|
@ -120,7 +121,7 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
|
|
||||||
final Button closeAction = widgetFactory.buttonLocalized(footer, CLOSE_WINDOW_TEXT_KEY);
|
final Button closeAction = widgetFactory.buttonLocalized(footer, CLOSE_WINDOW_TEXT_KEY);
|
||||||
closeAction.setLayoutData(new RowData(150, 30));
|
closeAction.setLayoutData(new RowData(150, 30));
|
||||||
closeAction.addListener(SWT.Selection, event -> closeRoom(proctoringWindowData));
|
closeAction.addListener(SWT.Selection, event -> closeRoom(proctoringGUIService, proctoringWindowData));
|
||||||
|
|
||||||
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
final BroadcastActionState broadcastActionState = new BroadcastActionState();
|
||||||
final String connectionTokens = getConnectionTokens(proctoringWindowData);
|
final String connectionTokens = getConnectionTokens(proctoringWindowData);
|
||||||
|
@ -256,11 +257,15 @@ public class JitsiMeetProctoringView implements RemoteProctoringView {
|
||||||
boolean chat = false;
|
boolean chat = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeRoom(final ProctoringWindowData proctoringWindowData) {
|
private void closeRoom(
|
||||||
this.pageService
|
final ProctoringGUIService proctoringGUIService,
|
||||||
.getCurrentUser()
|
final ProctoringWindowData proctoringWindowData) {
|
||||||
.getProctoringGUIService()
|
|
||||||
.closeRoom(proctoringWindowData.connectionData.roomName);
|
try {
|
||||||
|
proctoringGUIService.closeRoom(proctoringWindowData.connectionData.roomName);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Failed to close proctoring window properly: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class IsTownhallRoomAvailable extends RestCall<String> {
|
||||||
|
|
||||||
|
public IsTownhallRoomAvailable() {
|
||||||
|
super(new TypeKey<>(
|
||||||
|
CallType.GET_SINGLE,
|
||||||
|
EntityType.REMOTE_PROCTORING_ROOM,
|
||||||
|
new TypeReference<String>() {
|
||||||
|
}),
|
||||||
|
HttpMethod.GET,
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED,
|
||||||
|
API.EXAM_PROCTORING_ENDPOINT
|
||||||
|
+ API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
|
+ API.EXAM_PROCTORING_TOWNHALL_ROOM_AVAILABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -195,7 +195,7 @@ public class ProctoringGUIService {
|
||||||
closeWindow(name);
|
closeWindow(name);
|
||||||
final RoomConnectionData roomConnectionData = this.rooms.remove(name);
|
final RoomConnectionData roomConnectionData = this.rooms.remove(name);
|
||||||
if (roomConnectionData != null) {
|
if (roomConnectionData != null) {
|
||||||
// send reset of broadcast attributes to all in the room
|
// Send reset of broadcast attributes to all in the room
|
||||||
this.restService.getBuilder(SendProctoringBroadcastAttributes.class)
|
this.restService.getBuilder(SendProctoringBroadcastAttributes.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
||||||
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomConnectionData.roomName)
|
.withFormParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, roomConnectionData.roomName)
|
||||||
|
@ -209,7 +209,7 @@ public class ProctoringGUIService {
|
||||||
"Failed to send reset broadcast attribute instruction call for room: {}, cause: {}",
|
"Failed to send reset broadcast attribute instruction call for room: {}, cause: {}",
|
||||||
roomConnectionData.roomName,
|
roomConnectionData.roomName,
|
||||||
error.getMessage()));
|
error.getMessage()));
|
||||||
// send instruction to leave this room and join the own exam collecting room
|
// Send instruction to leave this room and join the own exam collecting room
|
||||||
if (!roomConnectionData.connections.isEmpty()) {
|
if (!roomConnectionData.connections.isEmpty()) {
|
||||||
this.restService.getBuilder(SendRejoinExamCollectionRoom.class)
|
this.restService.getBuilder(SendRejoinExamCollectionRoom.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
||||||
|
@ -221,6 +221,7 @@ public class ProctoringGUIService {
|
||||||
name,
|
name,
|
||||||
error.getMessage()));
|
error.getMessage()));
|
||||||
} else {
|
} else {
|
||||||
|
// Close town-hall room
|
||||||
this.restService.getBuilder(DisposeTownhallRoom.class)
|
this.restService.getBuilder(DisposeTownhallRoom.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
.withURIVariable(API.PARAM_MODEL_ID, roomConnectionData.examId)
|
||||||
.call()
|
.call()
|
||||||
|
|
|
@ -23,6 +23,8 @@ public interface RemoteProctoringRoomDAO {
|
||||||
|
|
||||||
Result<String> getRoomName(Long roomId);
|
Result<String> getRoomName(Long roomId);
|
||||||
|
|
||||||
|
boolean isTownhallRoomActive(Long examId);
|
||||||
|
|
||||||
Result<RemoteProctoringRoom> getTownhallRoom(Long examId);
|
Result<RemoteProctoringRoom> getTownhallRoom(Long examId);
|
||||||
|
|
||||||
Result<RemoteProctoringRoom> createTownhallRoom(Long examId, String subject);
|
Result<RemoteProctoringRoom> createTownhallRoom(Long examId, String subject);
|
||||||
|
|
|
@ -19,6 +19,8 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
@ -39,6 +41,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RemoteProctoringRoomDAOImpl.class);
|
||||||
|
|
||||||
private final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper;
|
private final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper;
|
||||||
|
|
||||||
protected RemoteProctoringRoomDAOImpl(
|
protected RemoteProctoringRoomDAOImpl(
|
||||||
|
@ -94,14 +98,9 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<RemoteProctoringRoom> createTownhallRoom(final Long examId, final String subject) {
|
public Result<RemoteProctoringRoom> createTownhallRoom(final Long examId, final String subject) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
// check first if town-hall room is not already active
|
|
||||||
final long active = this.remoteProctoringRoomRecordMapper.countByExample()
|
|
||||||
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
|
||||||
.and(RemoteProctoringRoomRecordDynamicSqlSupport.townhallRoom, isNotEqualTo(0))
|
|
||||||
.build()
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (active > 0) {
|
// Check first if town-hall room is not already active
|
||||||
|
if (isTownhallRoomActive(examId)) {
|
||||||
throw new IllegalStateException("Townhall, for exam: " + examId + " already exists");
|
throw new IllegalStateException("Townhall, for exam: " + examId + " already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +121,24 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
.onError(TransactionHandler::rollback);
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public boolean isTownhallRoomActive(final Long examId) {
|
||||||
|
try {
|
||||||
|
final long active = this.remoteProctoringRoomRecordMapper.countByExample()
|
||||||
|
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
||||||
|
.and(RemoteProctoringRoomRecordDynamicSqlSupport.townhallRoom, isNotEqualTo(0))
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
return (active > 0);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error(
|
||||||
|
"Failed to verify town-hall room activity for exam: {}. Mark it as active to avoid double openings",
|
||||||
|
examId, e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<RemoteProctoringRoom> saveRoom(final Long examId, final RemoteProctoringRoom room) {
|
public Result<RemoteProctoringRoom> saveRoom(final Long examId, final RemoteProctoringRoom room) {
|
||||||
|
|
|
@ -44,6 +44,12 @@ public interface ExamProctoringRoomService {
|
||||||
* name of an exam. */
|
* name of an exam. */
|
||||||
void updateProctoringCollectingRooms();
|
void updateProctoringCollectingRooms();
|
||||||
|
|
||||||
|
/** Indicates whether the town-hall room for a specified exam is active or not.
|
||||||
|
*
|
||||||
|
* @param examId the exam identifier
|
||||||
|
* @return true if the town-hall room for specified exam is active, false if not. */
|
||||||
|
boolean isTownhallRoomActive(Long examId);
|
||||||
|
|
||||||
/** This creates a town-hall room for a specific exam. The exam must be active and running
|
/** This creates a town-hall room for a specific exam. The exam must be active and running
|
||||||
* and there must be no other town-hall room already be active. An unique room name will be
|
* and there must be no other town-hall room already be active. An unique room name will be
|
||||||
* created and returned.
|
* created and returned.
|
||||||
|
|
|
@ -95,6 +95,11 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTownhallRoomActive(final Long examId) {
|
||||||
|
return this.remoteProctoringRoomDAO.isTownhallRoomActive(examId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<RemoteProctoringRoom> createTownhallRoom(final Long examId, final String subject) {
|
public Result<RemoteProctoringRoom> createTownhallRoom(final Long examId, final String subject) {
|
||||||
if (!this.examSessionService.isExamRunning(examId)) {
|
if (!this.examSessionService.isExamRunning(examId)) {
|
||||||
|
|
|
@ -304,6 +304,22 @@ public class ExamProctoringController {
|
||||||
Utils.toByteArray(connectionToken));
|
Utils.toByteArray(connectionToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.MODEL_ID_VAR_PATH_SEGMENT
|
||||||
|
+ API.EXAM_PROCTORING_TOWNHALL_ROOM_AVAILABLE,
|
||||||
|
method = RequestMethod.GET,
|
||||||
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
|
public String isTownhallRoomAvialbale(
|
||||||
|
@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) {
|
||||||
|
|
||||||
|
checkExamReadAccess(institutionId);
|
||||||
|
return String.valueOf(!this.examProcotringRoomService.isTownhallRoomActive(examId));
|
||||||
|
}
|
||||||
|
|
||||||
@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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue