SEBSERV-490 join proctoring in Ready state only for Exam without LMS
This commit is contained in:
parent
cfa9fba9cb
commit
74d4b1ff7d
4 changed files with 62 additions and 45 deletions
|
@ -251,7 +251,9 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
||||||
.and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name()))
|
.and(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomId, isNull())
|
||||||
|
.and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name()),
|
||||||
|
or(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.READY.name())))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -292,7 +294,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.build()
|
.build()
|
||||||
.execute()
|
.execute()
|
||||||
.stream()
|
.stream()
|
||||||
.map(r -> r.getConnectionToken())
|
.map(ClientConnectionRecord::getConnectionToken)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -305,6 +307,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
||||||
.and(ClientConnectionRecordDynamicSqlSupport.status, isNotEqualTo(ConnectionStatus.ACTIVE.name()))
|
.and(ClientConnectionRecordDynamicSqlSupport.status, isNotEqualTo(ConnectionStatus.ACTIVE.name()))
|
||||||
|
.and(ClientConnectionRecordDynamicSqlSupport.status, isNotEqualTo(ConnectionStatus.READY.name()))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -551,7 +554,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate, isNotEqualTo((byte) 0))
|
.where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate, isNotEqualTo((byte) 0))
|
||||||
.and(ClientConnectionRecordDynamicSqlSupport.examId, isIn(examIds))
|
.and(ClientConnectionRecordDynamicSqlSupport.examId, isIn(examIds))
|
||||||
.and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name()))
|
.and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name()),
|
||||||
|
or(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.READY.name())))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -588,7 +592,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
this.clientConnectionRecordMapper::update,
|
this.clientConnectionRecordMapper::update,
|
||||||
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
|
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
|
||||||
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupId).equalTo(groupId)
|
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupId).equalTo(groupId)
|
||||||
//.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0)
|
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0)
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId))
|
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
|
@ -66,7 +66,7 @@ public interface RemoteProctoringRoomService extends SessionUpdateTask {
|
||||||
* New client connections that are coming in and are established only mark itself for
|
* New client connections that are coming in and are established only mark itself for
|
||||||
* proctoring room update if proctoring is enabled for the specified exam. This batch processing
|
* proctoring room update if proctoring is enabled for the specified exam. This batch processing
|
||||||
* then makes the update synchronously to keep track on room creation and naming
|
* then makes the update synchronously to keep track on room creation and naming
|
||||||
*
|
* <p>
|
||||||
* If for a specified exam the town-hall room is active incoming client connection are instructed to
|
* If for a specified exam the town-hall room is active incoming client connection are instructed to
|
||||||
* join the town-hall room. If not, incoming client connection are instructed to join a collecting room. */
|
* join the town-hall room. If not, incoming client connection are instructed to join a collecting room. */
|
||||||
void updateProctoringCollectingRooms();
|
void updateProctoringCollectingRooms();
|
||||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -58,14 +59,10 @@ public class ExamSessionControlTask implements DisposableBean {
|
||||||
this.pingUpdateRate = pingUpdateRate;
|
this.pingUpdateRate = pingUpdateRate;
|
||||||
|
|
||||||
this.examUpdateTasks = new ArrayList<>(examUpdateTasks);
|
this.examUpdateTasks = new ArrayList<>(examUpdateTasks);
|
||||||
this.examUpdateTasks.sort((t1, t2) -> Integer.compare(
|
this.examUpdateTasks.sort(Comparator.comparingInt(ExamUpdateTask::examUpdateTaskProcessingOrder));
|
||||||
t1.examUpdateTaskProcessingOrder(),
|
|
||||||
t2.examUpdateTaskProcessingOrder()));
|
|
||||||
|
|
||||||
this.sessionUpdateTasks = new ArrayList<>(sessionUpdateTasks);
|
this.sessionUpdateTasks = new ArrayList<>(sessionUpdateTasks);
|
||||||
this.sessionUpdateTasks.sort((t1, t2) -> Integer.compare(
|
this.sessionUpdateTasks.sort(Comparator.comparingInt(SessionUpdateTask::sessionUpdateTaskProcessingOrder));
|
||||||
t1.sessionUpdateTaskProcessingOrder(),
|
|
||||||
t2.sessionUpdateTaskProcessingOrder()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener(SEBServerInitEvent.class)
|
@EventListener(SEBServerInitEvent.class)
|
||||||
|
|
|
@ -19,6 +19,8 @@ import java.util.stream.Stream;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.ScreenProctoringSettings;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
@ -258,16 +260,18 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
clientConnection);
|
clientConnection);
|
||||||
|
|
||||||
final ConnectionStatus currentStatus = clientConnection.getStatus();
|
final ConnectionStatus currentStatus = clientConnection.getStatus();
|
||||||
|
final ConnectionStatus newStatus = (StringUtils.isNotBlank(userSessionId) && currentStatus == ConnectionStatus.READY)
|
||||||
|
? ConnectionStatus.ACTIVE
|
||||||
|
: currentStatus;
|
||||||
final String signatureHash = StringUtils.isNotBlank(appSignatureKey)
|
final String signatureHash = StringUtils.isNotBlank(appSignatureKey)
|
||||||
? getSignatureHash(appSignatureKey, connectionToken, _examId)
|
? getSignatureHash(appSignatureKey, connectionToken, _examId)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
final ClientConnection updateConnection = new ClientConnection(
|
final ClientConnection updateConnection = new ClientConnection(
|
||||||
clientConnection.id,
|
clientConnection.id,
|
||||||
null,
|
null,
|
||||||
examId,
|
examId,
|
||||||
(StringUtils.isNotBlank(userSessionId) && currentStatus == ConnectionStatus.READY)
|
newStatus,
|
||||||
? ConnectionStatus.ACTIVE
|
|
||||||
: null,
|
|
||||||
null,
|
null,
|
||||||
updateUserSessionId,
|
updateUserSessionId,
|
||||||
StringUtils.isNotBlank(clientAddress) ? clientAddress : null,
|
StringUtils.isNotBlank(clientAddress) ? clientAddress : null,
|
||||||
|
@ -280,9 +284,9 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
applyScreenProctoring(_examId, newStatus),
|
||||||
null,
|
null,
|
||||||
null,
|
applyProctoring(_examId, newStatus),
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
signatureHash,
|
signatureHash,
|
||||||
null);
|
null);
|
||||||
|
@ -311,6 +315,8 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<ClientConnection> establishClientConnection(
|
public Result<ClientConnection> establishClientConnection(
|
||||||
final String connectionToken,
|
final String connectionToken,
|
||||||
|
@ -331,12 +337,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
|
|
||||||
connectionStatusIntegrityCheck(clientConnection, clientAddress);
|
connectionStatusIntegrityCheck(clientConnection, clientAddress);
|
||||||
checkInstitutionalIntegrity(institutionId, clientConnection);
|
checkInstitutionalIntegrity(institutionId, clientConnection);
|
||||||
checkExamIntegrity(
|
checkExamIntegrity(examId, clientConnection.examId, institutionId, clientConnection.connectionToken, clientConnection.info);
|
||||||
examId,
|
|
||||||
clientConnection.examId,
|
|
||||||
institutionId,
|
|
||||||
clientConnection.connectionToken,
|
|
||||||
clientConnection.info);
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug(
|
log.debug(
|
||||||
|
@ -350,28 +351,17 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
clientId,
|
clientId,
|
||||||
sebMachineName,
|
sebMachineName,
|
||||||
clientConnection);
|
clientConnection);
|
||||||
final Boolean proctoringEnabled = this.examAdminService
|
|
||||||
.isProctoringEnabled(clientConnection.examId)
|
|
||||||
.getOr(false);
|
|
||||||
final Boolean screenProctoringEnabled = this.examAdminService
|
|
||||||
.isScreenProctoringEnabled(clientConnection.examId)
|
|
||||||
.getOr(false);
|
|
||||||
|
|
||||||
final Long currentExamId = (examId != null) ? examId : clientConnection.examId;
|
|
||||||
final String currentVdiConnectionId = (clientId != null)
|
|
||||||
? clientId
|
|
||||||
: clientConnection.sebClientUserId;
|
|
||||||
|
|
||||||
|
|
||||||
|
final ConnectionStatus newStatus = StringUtils.isNotBlank(userSessionId) || alreadyAuthenticated(clientConnection)
|
||||||
|
? ConnectionStatus.ACTIVE
|
||||||
|
: ConnectionStatus.READY;
|
||||||
|
|
||||||
// create new ClientConnection for update
|
// create new ClientConnection for update
|
||||||
final ClientConnection establishedClientConnection = new ClientConnection(
|
final ClientConnection establishedClientConnection = new ClientConnection(
|
||||||
clientConnection.id,
|
clientConnection.id,
|
||||||
null,
|
null,
|
||||||
currentExamId,
|
_examId,
|
||||||
StringUtils.isNotBlank(userSessionId) || alreadyAuthenticated(clientConnection)
|
newStatus,
|
||||||
? ConnectionStatus.ACTIVE
|
|
||||||
: ConnectionStatus.READY,
|
|
||||||
null,
|
null,
|
||||||
updateUserSessionId,
|
updateUserSessionId,
|
||||||
StringUtils.isNotBlank(clientAddress) ? clientAddress : null,
|
StringUtils.isNotBlank(clientAddress) ? clientAddress : null,
|
||||||
|
@ -384,9 +374,9 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
screenProctoringEnabled,
|
applyScreenProctoring(_examId, newStatus),
|
||||||
null,
|
null,
|
||||||
proctoringEnabled,
|
applyProctoring(_examId, newStatus),
|
||||||
null,
|
null,
|
||||||
getSignatureHash(appSignatureKey, connectionToken, _examId),
|
getSignatureHash(appSignatureKey, connectionToken, _examId),
|
||||||
null);
|
null);
|
||||||
|
@ -394,7 +384,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
// ClientConnection integrity check
|
// ClientConnection integrity check
|
||||||
if (clientConnection.institutionId == null ||
|
if (clientConnection.institutionId == null ||
|
||||||
clientConnection.connectionToken == null ||
|
clientConnection.connectionToken == null ||
|
||||||
currentExamId == null ||
|
_examId == null ||
|
||||||
(clientConnection.clientAddress == null && clientAddress == null)) {
|
(clientConnection.clientAddress == null && clientAddress == null)) {
|
||||||
|
|
||||||
log.error("ClientConnection integrity violation, clientConnection: {}, updatedClientConnection: {}",
|
log.error("ClientConnection integrity violation, clientConnection: {}, updatedClientConnection: {}",
|
||||||
|
@ -835,10 +825,9 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
|
|
||||||
if (this.isDistributedSetup) {
|
if (this.isDistributedSetup) {
|
||||||
// if the cached Exam is not up-to-date anymore, we have to update the cache first
|
// if the cached Exam is not up-to-date anymore, we have to update the cache first
|
||||||
final Result<Exam> updateExamCache = this.examSessionService.updateExamCache(examId);
|
this.examSessionService
|
||||||
if (updateExamCache.hasError()) {
|
.updateExamCache(examId)
|
||||||
log.warn("Failed to update Exam-Cache for Exam: {}", examId);
|
.onError(error -> log.warn("Failed to update Exam-Cache for Exam: {}", examId));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentExamId != null && !examId.equals(currentExamId)) {
|
if (currentExamId != null && !examId.equals(currentExamId)) {
|
||||||
|
@ -922,4 +911,31 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
!clientConnection.userSessionId.equals(clientConnection.sebClientUserId) &&
|
!clientConnection.userSessionId.equals(clientConnection.sebClientUserId) &&
|
||||||
!clientConnection.userSessionId.equals(clientConnection.sebMachineName);
|
!clientConnection.userSessionId.equals(clientConnection.sebMachineName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean applyProctoring(final Long examId, final ConnectionStatus status) {
|
||||||
|
if (examId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Exam exam = this.examSessionCacheService.getRunningExam(examId);
|
||||||
|
final boolean proctoringEnabled = exam != null && BooleanUtils.toBoolean(
|
||||||
|
exam.getAdditionalAttribute(ProctoringServiceSettings.ATTR_ENABLE_PROCTORING));
|
||||||
|
|
||||||
|
return isApplyProctoring(status, exam) && proctoringEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean applyScreenProctoring(final Long examId, final ConnectionStatus status) {
|
||||||
|
if (examId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Exam exam = this.examSessionCacheService.getRunningExam(examId);
|
||||||
|
final boolean screenProctoringEnabled = exam != null && BooleanUtils.toBoolean(
|
||||||
|
exam.getAdditionalAttribute(ScreenProctoringSettings.ATTR_ENABLE_SCREEN_PROCTORING));
|
||||||
|
|
||||||
|
return isApplyProctoring(status, exam) && screenProctoringEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isApplyProctoring(final ConnectionStatus status, final Exam exam) {
|
||||||
|
return (exam != null && exam.lmsSetupId == null && status == ConnectionStatus.READY) ||
|
||||||
|
status == ConnectionStatus.ACTIVE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue