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,81 +280,26 @@ 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 (clientTable.isStatusHidden(ConnectionStatus.CLOSED)) {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (clientTable.isStatusHidden(ConnectionStatus.CONNECTION_REQUESTED)) {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(
 | 
					 | 
				
			||||||
                                                hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(
 | 
					 | 
				
			||||||
                                                showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (clientTable.isStatusHidden(ConnectionStatus.DISABLED)) {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
 | 
					 | 
				
			||||||
                        .withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
					 | 
				
			||||||
                        .noEventPropagation()
 | 
					 | 
				
			||||||
                        .withSwitchAction(
 | 
					 | 
				
			||||||
                                actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
 | 
					 | 
				
			||||||
                                        .withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
					 | 
				
			||||||
                                        .noEventPropagation()
 | 
					 | 
				
			||||||
                                        .create())
 | 
					 | 
				
			||||||
                        .publish();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isExamSupporter.getAsBoolean()) {
 | 
				
			||||||
 | 
					            addFilterActions(actionBuilder, clientTable, isExamSupporter);
 | 
				
			||||||
 | 
					            addProctoringActions(
 | 
				
			||||||
 | 
					                    currentUser.getProctoringGUIService(),
 | 
				
			||||||
 | 
					                    pageContext,
 | 
				
			||||||
 | 
					                    content,
 | 
				
			||||||
 | 
					                    actionBuilder);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final ProctoringSettings proctoringSettings = restService
 | 
					    private void addProctoringActions(
 | 
				
			||||||
 | 
					            final ProctoringGUIService proctoringGUIService,
 | 
				
			||||||
 | 
					            final PageContext pageContext,
 | 
				
			||||||
 | 
					            final Composite parent,
 | 
				
			||||||
 | 
					            final PageActionBuilder actionBuilder) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final EntityKey entityKey = pageContext.getEntityKey();
 | 
				
			||||||
 | 
					        final ProctoringSettings proctoringSettings = this.restService
 | 
				
			||||||
                .getBuilder(GetProctoringSettings.class)
 | 
					                .getBuilder(GetProctoringSettings.class)
 | 
				
			||||||
                .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
 | 
					                .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
 | 
				
			||||||
                .call()
 | 
					                .call()
 | 
				
			||||||
| 
						 | 
					@ -359,7 +309,7 @@ public class MonitoringRunningExam implements TemplateComposer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM)
 | 
				
			||||||
                    .withEntityKey(entityKey)
 | 
					                    .withEntityKey(entityKey)
 | 
				
			||||||
                    .withExec(this::toggleTownhallRoom)
 | 
					                    .withExec(action -> this.toggleTownhallRoom(proctoringGUIService, action))
 | 
				
			||||||
                    .noEventPropagation()
 | 
					                    .noEventPropagation()
 | 
				
			||||||
                    .publish();
 | 
					                    .publish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -375,34 +325,126 @@ public class MonitoringRunningExam implements TemplateComposer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            final Map<String, Pair<RemoteProctoringRoom, TreeItem>> availableRooms = new HashMap<>();
 | 
					            final Map<String, Pair<RemoteProctoringRoom, TreeItem>> availableRooms = new HashMap<>();
 | 
				
			||||||
            updateRoomActions(
 | 
					            updateRoomActions(
 | 
				
			||||||
                    entityKey,
 | 
					 | 
				
			||||||
                    pageContext,
 | 
					                    pageContext,
 | 
				
			||||||
                    availableRooms,
 | 
					                    availableRooms,
 | 
				
			||||||
                    actionBuilder,
 | 
					                    actionBuilder,
 | 
				
			||||||
                    proctoringSettings);
 | 
					                    proctoringSettings,
 | 
				
			||||||
 | 
					                    proctoringGUIService);
 | 
				
			||||||
            this.serverPushService.runServerPush(
 | 
					            this.serverPushService.runServerPush(
 | 
				
			||||||
                    new ServerPushContext(
 | 
					                    new ServerPushContext(
 | 
				
			||||||
                            content,
 | 
					                            parent,
 | 
				
			||||||
                            Utils.truePredicate(),
 | 
					                            Utils.truePredicate(),
 | 
				
			||||||
                            createServerPushUpdateErrorHandler(this.pageService, pageContext)),
 | 
					                            createServerPushUpdateErrorHandler(this.pageService, pageContext)),
 | 
				
			||||||
                    this.proctoringRoomUpdateInterval,
 | 
					                    this.proctoringRoomUpdateInterval,
 | 
				
			||||||
                    context -> updateRoomActions(
 | 
					                    context -> updateRoomActions(
 | 
				
			||||||
                            entityKey,
 | 
					 | 
				
			||||||
                            pageContext,
 | 
					                            pageContext,
 | 
				
			||||||
                            availableRooms,
 | 
					                            availableRooms,
 | 
				
			||||||
                            actionBuilder,
 | 
					                            actionBuilder,
 | 
				
			||||||
                            proctoringSettings));
 | 
					                            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()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
 | 
				
			||||||
 | 
					                    .withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
				
			||||||
 | 
					                    .noEventPropagation()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addRequestedFilterAction(
 | 
				
			||||||
 | 
					            final PageActionBuilder actionBuilder,
 | 
				
			||||||
 | 
					            final ClientConnectionTable clientTable) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (clientTable.isStatusHidden(ConnectionStatus.CONNECTION_REQUESTED)) {
 | 
				
			||||||
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
 | 
				
			||||||
 | 
					                    .withExec(showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
				
			||||||
 | 
					                    .noEventPropagation()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(
 | 
				
			||||||
 | 
					                                            hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
 | 
				
			||||||
 | 
					                    .withExec(hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
				
			||||||
 | 
					                    .noEventPropagation()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(
 | 
				
			||||||
 | 
					                                            showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addClosedFilterAction(
 | 
				
			||||||
 | 
					            final PageActionBuilder actionBuilder,
 | 
				
			||||||
 | 
					            final ClientConnectionTable clientTable) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (clientTable.isStatusHidden(ConnectionStatus.CLOSED)) {
 | 
				
			||||||
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
 | 
				
			||||||
 | 
					                    .withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
				
			||||||
 | 
					                    .noEventPropagation()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
 | 
				
			||||||
 | 
					                    .withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
				
			||||||
 | 
					                    .noEventPropagation()
 | 
				
			||||||
 | 
					                    .withSwitchAction(
 | 
				
			||||||
 | 
					                            actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
 | 
				
			||||||
 | 
					                                    .withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
 | 
				
			||||||
 | 
					                                    .noEventPropagation()
 | 
				
			||||||
 | 
					                                    .create())
 | 
				
			||||||
 | 
					                    .publish();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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,45 +538,59 @@ 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)) {
 | 
				
			||||||
            this.pageService.firePageEvent(
 | 
					            final boolean townhallRoomFromThisUser = proctoringGUIService
 | 
				
			||||||
                    new ActionActivationEvent(
 | 
					                    .getTownhallRoom(entityKey.modelId) != null;
 | 
				
			||||||
                            true,
 | 
					            if (townhallRoomFromThisUser) {
 | 
				
			||||||
                            new Tuple<>(
 | 
					                this.pageService.firePageEvent(
 | 
				
			||||||
                                    ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
 | 
					                        new ActionActivationEvent(
 | 
				
			||||||
                                    ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
 | 
					                                true,
 | 
				
			||||||
                    pageContext);
 | 
					                                new Tuple<>(
 | 
				
			||||||
 | 
					                                        ActionDefinition.MONITOR_EXAM_OPEN_TOWNHALL_PROCTOR_ROOM,
 | 
				
			||||||
 | 
					                                        ActionDefinition.MONITOR_EXAM_CLOSE_TOWNHALL_PROCTOR_ROOM)),
 | 
				
			||||||
 | 
					                        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