SEBSERV-435 fixes and preparing integration configuration

This commit is contained in:
anhefti 2023-11-02 15:01:29 +01:00
parent 99ea2472f4
commit 6e5d5e7710
10 changed files with 61 additions and 22 deletions

View file

@ -94,15 +94,15 @@ public class ProctoringServlet extends HttpServlet {
// https://stackoverflow.com/questions/46582/response-redirect-with-post-instead-of-get // https://stackoverflow.com/questions/46582/response-redirect-with-post-instead-of-get
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("<html>"); // sb.append("<html>");
sb.append("<body onload='document.forms[\"form\"].submit()'>"); // sb.append("<body onload='document.forms[\"form\"].submit()'>");
sb.append("<form name='form' action='"); // sb.append("<form name='form' action='");
sb.append(data.loginLocation).append("' method='post'>"); // sb.append( "" /* data.loginLocation */).append("' method='post'>");
sb.append("</input type='hidden' name='username' value='").append("super-admin").append("'>"); // sb.append("</input type='hidden' name='username' value='").append("super-admin").append("'>");
sb.append("</input type='hidden' name='password' type='password' value='").append("admin").append("'>"); // sb.append("</input type='hidden' name='password' type='password' value='").append("admin").append("'>");
sb.append("</form>"); // sb.append("</form>");
sb.append("</body>"); // sb.append("</body>");
sb.append("</html>"); // sb.append("</html>");
resp.getOutputStream().println(sb.toString()); resp.getOutputStream().println(sb.toString());
} }

View file

@ -148,6 +148,11 @@ public interface ClientConnectionDAO extends
key = "#connectionToken") key = "#connectionToken")
Result<Void> assignToScreenProctoringGroup(Long connectionId, String connectionToken, Long groupId); Result<Void> assignToScreenProctoringGroup(Long connectionId, String connectionToken, Long groupId);
@CacheEvict(
cacheNames = ExamSessionCacheService.CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
key = "#connectionToken")
Result<Void> markScreenProcotringApplied(Long connectionId, String connectionToken);
/** Get a ClientConnection by connection token. /** Get a ClientConnection by connection token.
* *
* @param connectionToken the connection token * @param connectionToken the connection token

View file

@ -532,7 +532,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
final List<ClientConnectionRecord> execute = this.clientConnectionRecordMapper final List<ClientConnectionRecord> execute = this.clientConnectionRecordMapper
.selectByExample() .selectByExample()
.where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupId, isNull()) .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()))
.build() .build()
@ -571,6 +571,20 @@ 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)
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId))
.build()
.execute();
})
.onError(TransactionHandler::rollback);
}
@Override
public Result<Void> markScreenProcotringApplied(final Long connectionId, final String connectionToken) {
return Result.tryCatch(() -> {
UpdateDSL.updateWithMapper(
this.clientConnectionRecordMapper::update,
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0) .set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0)
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId)) .where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId))
.build() .build()
@ -1136,4 +1150,5 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.build() .build()
.execute(); .execute();
} }
} }

View file

@ -381,12 +381,13 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
} }
} }
// if screen proctoring enabled mark for screen proctoring update
// TODO
final Boolean proctoringEnabled = this.examAdminService final Boolean proctoringEnabled = this.examAdminService
.isProctoringEnabled(clientConnection.examId) .isProctoringEnabled(clientConnection.examId)
.getOr(false); .getOr(false);
final Boolean screenProctoringEnabled = this.examAdminService
.isScreenProctoringEnabled(clientConnection.examId)
.getOr(false);
final Long currentExamId = (examId != null) ? examId : clientConnection.examId; final Long currentExamId = (examId != null) ? examId : clientConnection.examId;
final String currentVdiConnectionId = (clientId != null) final String currentVdiConnectionId = (clientId != null)
? clientId ? clientId
@ -410,7 +411,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
null, null,
null, null,
null, null,
null, screenProctoringEnabled,
null, null,
proctoringEnabled, proctoringEnabled,
null, null,

View file

@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -41,8 +42,10 @@ public class SEBClientPingBatchService implements SEBClientPingService {
private final ThreadPoolTaskScheduler threadPoolTaskScheduler; private final ThreadPoolTaskScheduler threadPoolTaskScheduler;
private final long schendulerInterval; private final long schendulerInterval;
private final Set<String> pingKeys = new HashSet<>();
private final Map<String, String> pings = new ConcurrentHashMap<>(); private final Map<String, String> pings = new ConcurrentHashMap<>();
private final Map<String, String> instructions = new ConcurrentHashMap<>(); private final Map<String, String> instructions = new ConcurrentHashMap<>();
private final Set<String> confirmedInstructions = Collections.synchronizedSet(new HashSet<>());
private ScheduledFuture<?> scheduleAtFixedRate = null; private ScheduledFuture<?> scheduleAtFixedRate = null;
@ -83,9 +86,10 @@ public class SEBClientPingBatchService implements SEBClientPingService {
} }
try { try {
final Set<String> connections = new HashSet<>(this.pings.keySet()); this.pingKeys.clear();
this.pingKeys.addAll(this.pings.keySet());
connections.stream().forEach(cid -> processPing( //final Set<String> connections = new HashSet<>(this.pings.keySet());
this.pingKeys.stream().forEach(cid -> processPing(
cid, cid,
this.pings.remove(cid), this.pings.remove(cid),
Utils.getMillisecondsNow())); Utils.getMillisecondsNow()));
@ -111,10 +115,10 @@ public class SEBClientPingBatchService implements SEBClientPingService {
System.out.println("************ put instructionConfirm: " + instructionConfirm + " instructions: " System.out.println("************ put instructionConfirm: " + instructionConfirm + " instructions: "
+ this.instructions); + this.instructions);
this.pings.put(connectionToken, instructionConfirm); this.pings.put(connectionToken, instructionConfirm);
// TODO is this a good idea or is there another better way to deal with instruction confirm synchronization? // // TODO is this a good idea or is there another better way to deal with instruction confirm synchronization?
if (instruction != null && instruction.contains("\"instruction-confirm\":\"" + instructionConfirm + "\"")) { // if (instruction != null && instruction.contains("\"instruction-confirm\":\"" + instructionConfirm + "\"")) {
return null; // return null;
} // }
} else if (!this.pings.containsKey(connectionToken)) { } else if (!this.pings.containsKey(connectionToken)) {
this.pings.put(connectionToken, StringUtils.EMPTY); this.pings.put(connectionToken, StringUtils.EMPTY);
} }
@ -147,6 +151,10 @@ public class SEBClientPingBatchService implements SEBClientPingService {
this.sebClientInstructionService.confirmInstructionDone(connectionToken, instructionConfirm); this.sebClientInstructionService.confirmInstructionDone(connectionToken, instructionConfirm);
} }
if (this.instructions.containsKey(connectionToken)) {
return;
}
final String instructionJSON = this.sebClientInstructionService.getInstructionJSON(connectionToken); final String instructionJSON = this.sebClientInstructionService.getInstructionJSON(connectionToken);
if (instructionJSON != null) { if (instructionJSON != null) {
this.instructions.put(connectionToken, instructionJSON); this.instructions.put(connectionToken, instructionJSON);

View file

@ -33,7 +33,7 @@ public class SEBClientPingServiceFactory {
public SEBClientPingServiceFactory( public SEBClientPingServiceFactory(
final Collection<SEBClientPingService> serviceBeans, final Collection<SEBClientPingService> serviceBeans,
@Value("${sebserver.webservice.api.exam.session.ping.service.type:BLOCKING}") final String serviceType) { @Value("${sebserver.webservice.api.exam.session.ping.service.strategy:BLOCKING}") final String serviceType) {
SEBClientPingService.PingServiceType serviceTypeToSet = SEBClientPingService.PingServiceType.BLOCKING; SEBClientPingService.PingServiceType serviceTypeToSet = SEBClientPingService.PingServiceType.BLOCKING;
try { try {

View file

@ -485,6 +485,8 @@ class ScreenProctoringAPIBinding {
final ScreenProctoringGroup localGroup, final ScreenProctoringGroup localGroup,
final ClientConnectionRecord clientConnection) { final ClientConnectionRecord clientConnection) {
// TODO check if the Session with token UUID already exists and if true, return the token
final String token = clientConnection.getConnectionToken(); final String token = clientConnection.getConnectionToken();
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(examId); final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(examId);
final String uri = UriComponentsBuilder final String uri = UriComponentsBuilder

View file

@ -316,6 +316,10 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
// create instruction for SEB and add it to instruction queue for SEB connection // create instruction for SEB and add it to instruction queue for SEB connection
registerJoinInstruction(ccRecord, spsSessionToken, group, runningExam); registerJoinInstruction(ccRecord, spsSessionToken, group, runningExam);
this.clientConnectionDAO
.markScreenProcotringApplied(ccRecord.getId(), ccRecord.getConnectionToken())
.getOrThrow();
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to apply screen proctoring session to SEB with connection: ", ccRecord, e); log.error("Failed to apply screen proctoring session to SEB with connection: ", ccRecord, e);

View file

@ -45,6 +45,7 @@ sebserver.webservice.api.exam.endpoint=/exam-api
sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery sebserver.webservice.api.exam.endpoint.discovery=${sebserver.webservice.api.exam.endpoint}/discovery
sebserver.webservice.api.exam.endpoint.v1=${sebserver.webservice.api.exam.endpoint}/v1 sebserver.webservice.api.exam.endpoint.v1=${sebserver.webservice.api.exam.endpoint}/v1
sebserver.webservice.api.exam.event-handling-strategy=ASYNC_BATCH_STORE_STRATEGY sebserver.webservice.api.exam.event-handling-strategy=ASYNC_BATCH_STORE_STRATEGY
sebserver.webservice.api.exam.session.ping.service.strategy=BATCH
sebserver.webservice.api.exam.enable-indicator-cache=true sebserver.webservice.api.exam.enable-indicator-cache=true
sebserver.webservice.api.exam.defaultPingInterval=1000 sebserver.webservice.api.exam.defaultPingInterval=1000
sebserver.webservice.api.pagination.maxPageSize=500 sebserver.webservice.api.pagination.maxPageSize=500

View file

@ -65,4 +65,7 @@ sebserver.ssl.redirect.html.port=8080
# features # features
sebserver.feature.seb.screenProctoring=false sebserver.feature.seb.screenProctoring=false
sebserver.feature.seb.screenProctoring.bundled=true
sebserver.feature.seb.screenProctoring.bundled.clientId=sebserverClient
sebserver.feature.seb.screenProctoring.bundled.clientPassword=${sebserver.password}
sebserver.feature.CollectingRoomStrategy.SEB-GROUP=false sebserver.feature.CollectingRoomStrategy.SEB-GROUP=false