diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
index bf8d52d4..44ad452f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java
@@ -905,6 +905,11 @@ public enum ActionDefinition {
ImageIcon.LOCK,
PageStateDefinitionImpl.MONITORING_CLIENT_CONNECTION,
ActionCategory.FORM),
+ MONITOR_EXAM_CLIENT_DISABLE_CONNECTION(
+ new LocTextKey("sebserver.monitoring.exam.connection.action.disable"),
+ ImageIcon.DISABLE,
+ PageStateDefinitionImpl.MONITORING_CLIENT_CONNECTION,
+ ActionCategory.FORM),
MONITOR_EXAM_CLIENT_CONNECTION_PROCTORING(
new LocTextKey("sebserver.monitoring.exam.connection.action.proctoring"),
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java
index 9f066cdc..2d67a563 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java
@@ -61,6 +61,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.clientgroup.
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.indicator.GetIndicators;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ConfirmPendingClientNotification;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DisableClientConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionData;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionSecurityKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetPendingClientNotifications;
@@ -100,6 +101,10 @@ public class MonitoringClientConnection implements TemplateComposer {
new LocTextKey("sebserver.monitoring.exam.connection.action.instruction.quit.confirm");
private static final LocTextKey CONFIRM_OPEN_SINGLE_ROOM =
new LocTextKey("sebserver.monitoring.exam.connection.action.singleroom.confirm");
+ private static final LocTextKey CONFIRM_CANCEL_MISSING =
+ new LocTextKey("sebserver.monitoring.exam.connection.action.cancel.confirm");
+ private static final LocTextKey CONFIRM_CANCEL_ACTIVE =
+ new LocTextKey("sebserver.monitoring.exam.connection.action.cancel.active.info");
private static final LocTextKey EVENT_LIST_TITLE_KEY =
new LocTextKey("sebserver.monitoring.exam.connection.eventlist.title");
@@ -402,7 +407,21 @@ public class MonitoringClientConnection implements TemplateComposer {
some -> new HashSet<>(Arrays.asList(connectionToken))))
.noEventPropagation()
.publishIf(() -> isExamSupporter.getAsBoolean() &&
- connectionData.clientConnection.status.clientActiveStatus);
+ connectionData.clientConnection.status.clientActiveStatus)
+
+ .newAction(ActionDefinition.MONITOR_EXAM_CLIENT_DISABLE_CONNECTION)
+ .withParentEntityKey(exam.getEntityKey())
+ .withEntityKey(new EntityKey(
+ connectionData.clientConnection.connectionToken,
+ EntityType.CLIENT_CONNECTION))
+ .withConfirm(() -> clientConnectionDetails.hasMissingPing()
+ ? CONFIRM_CANCEL_MISSING
+ : null)
+ .withExec(action -> this.disableClientConnection(action, clientConnectionDetails))
+ .noEventPropagation()
+ .publishIf(() -> isExamSupporter.getAsBoolean() &&
+ (connectionData.clientConnection.status == ConnectionStatus.ACTIVE ||
+ connectionData.clientConnection.status == ConnectionStatus.CLOSED));
if (clientConnectionDetails.checkSecurityGrant) {
final SecurityKey securityKey = this.pageService
@@ -464,6 +483,30 @@ public class MonitoringClientConnection implements TemplateComposer {
}
}
+ private PageAction disableClientConnection(
+ final PageAction action,
+ final ClientConnectionDetails clientConnectionDetails) {
+
+ final EntityKey entityKey = action.getEntityKey();
+ final EntityKey parentEntityKey = action.getParentEntityKey();
+
+ if (clientConnectionDetails.isActive() && !clientConnectionDetails.hasMissingPing()) {
+ action.pageContext().publishInfo(CONFIRM_CANCEL_ACTIVE);
+ return action;
+ }
+
+ this.pageService.getRestService()
+ .getBuilder(DisableClientConnection.class)
+ .withURIVariable(API.PARAM_PARENT_MODEL_ID, parentEntityKey.modelId)
+ .withFormParam(
+ Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN,
+ entityKey.modelId)
+ .call()
+ .onError(error -> action.pageContext().notifyUnexpectedError(error));
+
+ return action;
+ }
+
private PageAction confirmNotification(
final PageAction pageAction,
final ClientConnectionData connectionData,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java
index 1b9eb28b..214b48be 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java
@@ -172,6 +172,11 @@ public class ClientConnectionDetails implements MonitoringEntry {
return this.connectionData.clientConnection.status;
}
+ public boolean isActive() {
+ return this.connectionData.clientConnection.status != null
+ && this.connectionData.clientConnection.status.clientActiveStatus;
+ }
+
@Override
public boolean hasMissingPing() {
return (this.connectionData != null) ? this.connectionData.missingPing : false;
diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties
index 376cbdc8..b3db2ad0 100644
--- a/src/main/resources/messages.properties
+++ b/src/main/resources/messages.properties
@@ -2187,6 +2187,8 @@ sebserver.monitoring.exam.connection.notificationlist.actions=
sebserver.monitoring.exam.connection.action.confirm.notification=Confirm Notification
sebserver.monitoring.exam.connection.action.confirm.notification.text=Are you sure you want to confirm this pending notification?
Note that this will send a notification confirmation instruction to the SEB client and remove this notification from the pending list.
sebserver.monitoring.exam.connection.action.grant.signaturekey=Grant App Signature Key
+sebserver.monitoring.exam.connection.action.cancel.confirm=Are you sure to cancel this missing SEB client connection?
+sebserver.monitoring.exam.connection.action.cancel.active.info=This SEB client connection is still active and cannot be canceled.
Please quit it first.
sebserver.monitoring.exam.connection.notificationlist.pleaseSelect=At first please select a notification form the Pending Notification list
sebserver.monitoring.exam.connection.notificationlist.title=Pending Notification