SEBSERV-435 improved SEB Server SPS user account sync
This commit is contained in:
parent
6a0d53c8c4
commit
9bda8630f6
9 changed files with 81 additions and 14 deletions
|
@ -180,7 +180,9 @@ public class MonitoringProctoringService {
|
||||||
proctoringGUIService,
|
proctoringGUIService,
|
||||||
room));
|
room));
|
||||||
|
|
||||||
if (proctoringSettings.enabledFeatures.contains(ProctoringFeature.TOWN_HALL)) {
|
if (BooleanUtils.isTrue(proctoringSettings.enableProctoring) &&
|
||||||
|
proctoringSettings.enabledFeatures.contains(ProctoringFeature.TOWN_HALL)) {
|
||||||
|
|
||||||
updateTownhallButton(proctoringGUIService, pageContext);
|
updateTownhallButton(proctoringGUIService, pageContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -499,8 +499,6 @@ public class UserDAOImpl implements UserDAO {
|
||||||
this.userRecordMapper
|
this.userRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(UserRecordDynamicSqlSupport.username, isEqualTo(username))
|
.where(UserRecordDynamicSqlSupport.username, isEqualTo(username))
|
||||||
.and(UserRecordDynamicSqlSupport.active,
|
|
||||||
isEqualTo(BooleanUtils.toInteger(true)))
|
|
||||||
.build()
|
.build()
|
||||||
.execute());
|
.execute());
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,4 +90,7 @@ public interface ScreenProctoringService extends SessionUpdateTask {
|
||||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||||
void synchronizeSPSUser(final String userUUID);
|
void synchronizeSPSUser(final String userUUID);
|
||||||
|
|
||||||
|
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||||
|
void deleteSPSUser(String userUUID);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,8 +494,9 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
.getConnectionData(connectionToken)
|
.getConnectionData(connectionToken)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
// A connection can only be disabled if we have a missing ping
|
// A connection can only be disabled if we have a missing ping or for closed connections
|
||||||
if (!BooleanUtils.isTrue(connectionData.getMissingPing())) {
|
if (connectionData.clientConnection.status != ConnectionStatus.CLOSED &&
|
||||||
|
!BooleanUtils.isTrue(connectionData.getMissingPing())) {
|
||||||
return connectionData.clientConnection;
|
return connectionData.clientConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,7 @@ class ScreenProctoringAPIBinding {
|
||||||
.toUriString();
|
.toUriString();
|
||||||
|
|
||||||
final ResponseEntity<String> exchange = apiTemplate.exchange(
|
final ResponseEntity<String> exchange = apiTemplate.exchange(
|
||||||
uri, HttpMethod.POST, null, apiTemplate.getHeaders());
|
uri, HttpMethod.GET, null, apiTemplate.getHeaders());
|
||||||
|
|
||||||
if (exchange.getStatusCode() == HttpStatus.OK) {
|
if (exchange.getStatusCode() == HttpStatus.OK) {
|
||||||
log.info("Synchronize SPS user account for SEB Server user account with id: {} ", userUUID);
|
log.info("Synchronize SPS user account for SEB Server user account with id: {} ", userUUID);
|
||||||
|
@ -386,6 +386,30 @@ class ScreenProctoringAPIBinding {
|
||||||
log.error("Failed to synchronize user accounts with SPS for exam: {}", exam);
|
log.error("Failed to synchronize user accounts with SPS for exam: {}", exam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void deleteSPSUser(final String userUUID) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(null);
|
||||||
|
|
||||||
|
final String uri = UriComponentsBuilder
|
||||||
|
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||||
|
.path(SPS_API.USER_ACCOUNT_ENDPOINT + userUUID)
|
||||||
|
.build()
|
||||||
|
.toUriString();
|
||||||
|
|
||||||
|
final ResponseEntity<String> exchange = apiTemplate.exchange(
|
||||||
|
uri, HttpMethod.DELETE, null, apiTemplate.getHeaders());
|
||||||
|
|
||||||
|
if (exchange.getStatusCode() == HttpStatus.OK) {
|
||||||
|
log.info("Successfully deleted User Account on SPS for user: {}", userUUID);
|
||||||
|
} else {
|
||||||
|
log.error("Failed to delete user account on SPS for user: {} response: {}", userUUID, exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Failed to delete user account on SPS for user: {}", userUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** This is called when an exam has changed its parameter and needs data update on SPS side
|
/** This is called when an exam has changed its parameter and needs data update on SPS side
|
||||||
*
|
*
|
||||||
|
@ -583,7 +607,7 @@ class ScreenProctoringAPIBinding {
|
||||||
.byModelId(userUUID)
|
.byModelId(userUUID)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
final SEBServerUser accountInfo = this.userDAO
|
final SEBServerUser accountInfo = this.userDAO
|
||||||
.sebServerUserByUsername(userInfo.name)
|
.sebServerUserByUsername(userInfo.username)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
final UserMod userMod = getUserModifications(userInfo, accountInfo);
|
final UserMod userMod = getUserModifications(userInfo, accountInfo);
|
||||||
|
@ -600,8 +624,24 @@ class ScreenProctoringAPIBinding {
|
||||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||||
log.warn("Failed to synchronize user account on SPS: {}", exchange);
|
log.warn("Failed to synchronize user account on SPS: {}", exchange);
|
||||||
} else {
|
} else {
|
||||||
log.info("Successfully synchronize user account on SPS for user: ");
|
log.info("Successfully synchronize user account on SPS for user: {}", userUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync activity
|
||||||
|
final String activityURI = UriComponentsBuilder
|
||||||
|
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||||
|
.path(SPS_API.USER_ACCOUNT_ENDPOINT)
|
||||||
|
.pathSegment(userUUID)
|
||||||
|
.path(BooleanUtils.isTrue(userInfo.active) ? "/active" : "/inactive")
|
||||||
|
.build()
|
||||||
|
.toUriString();
|
||||||
|
final ResponseEntity<String> activityRequest = apiTemplate.exchange(
|
||||||
|
activityURI, HttpMethod.POST, jsonBody, apiTemplate.getHeaders());
|
||||||
|
|
||||||
|
if (activityRequest.getStatusCode() != HttpStatus.OK) {
|
||||||
|
log.warn("Failed to synchronize activity for user account on SPS: {}", activityRequest);
|
||||||
|
} else {
|
||||||
|
log.info("Successfully synchronize activity for user account on SPS for user: {}", userUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
|
|
@ -15,12 +15,14 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
|
@ -262,6 +264,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||||
public void synchronizeSPSUser(final String userUUID) {
|
public void synchronizeSPSUser(final String userUUID) {
|
||||||
|
|
||||||
if (!webserviceInfo.getScreenProctoringServiceBundle().bundled) {
|
if (!webserviceInfo.getScreenProctoringServiceBundle().bundled) {
|
||||||
|
@ -271,6 +274,17 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
||||||
this.screenProctoringAPIBinding.synchronizeUserAccount(userUUID);
|
this.screenProctoringAPIBinding.synchronizeUserAccount(userUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||||
|
public void deleteSPSUser(final String userUUID) {
|
||||||
|
|
||||||
|
if (!webserviceInfo.getScreenProctoringServiceBundle().bundled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.screenProctoringAPIBinding.deleteSPSUser(userUUID);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyExamStarted(final ExamStartedEvent event) {
|
public void notifyExamStarted(final ExamStartedEvent event) {
|
||||||
final Exam exam = event.exam;
|
final Exam exam = event.exam;
|
||||||
|
|
|
@ -15,6 +15,8 @@ import java.util.List;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Pair;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
||||||
import org.mybatis.dynamic.sql.SqlTable;
|
import org.mybatis.dynamic.sql.SqlTable;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
@ -156,6 +158,13 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
return userInfoResult;
|
return userInfoResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Result<Pair<UserInfo, EntityProcessingReport>> notifyDeleted(final Pair<UserInfo, EntityProcessingReport> pair) {
|
||||||
|
final Result<Pair<UserInfo, EntityProcessingReport>> result = super.notifyDeleted(pair);
|
||||||
|
this.screenProctoringService.deleteSPSUser(pair.a.uuid);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.PASSWORD_PATH_SEGMENT,
|
path = API.PASSWORD_PATH_SEGMENT,
|
||||||
method = RequestMethod.PUT,
|
method = RequestMethod.PUT,
|
||||||
|
|
|
@ -64,6 +64,6 @@ management.endpoints.web.exposure.include=logfile,loggers,jolokia
|
||||||
management.endpoints.web.path-mapping.jolokia=jmx
|
management.endpoints.web.path-mapping.jolokia=jmx
|
||||||
|
|
||||||
sebserver.feature.seb.screenProctoring.bundled=true
|
sebserver.feature.seb.screenProctoring.bundled=true
|
||||||
sebserver.feature.seb.screenProctoring.bundled.url=localhost:8090
|
sebserver.feature.seb.screenProctoring.bundled.url=http://localhost:8090
|
||||||
sebserver.feature.seb.screenProctoring.bundled.clientId=sebserverClient
|
sebserver.feature.seb.screenProctoring.bundled.clientId=sebserverClient
|
||||||
sebserver.feature.seb.screenProctoring.bundled.sebserveraccount.username=SEBServerAPIAccount
|
sebserver.feature.seb.screenProctoring.bundled.sebserveraccount.username=SEBServerAPIAccount
|
|
@ -2437,7 +2437,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
||||||
connections = connectionsCall.get();
|
connections = connectionsCall.get();
|
||||||
assertFalse(connections.isEmpty());
|
assertFalse(connections.isEmpty());
|
||||||
conData = connections.iterator().next();
|
conData = connections.iterator().next();
|
||||||
assertEquals("CLOSED", conData.clientConnection.status.name());
|
assertEquals("DISABLED", conData.clientConnection.status.name());
|
||||||
|
|
||||||
// get client logs
|
// get client logs
|
||||||
final Result<Page<ExtendedClientEvent>> clientLogPage = restService
|
final Result<Page<ExtendedClientEvent>> clientLogPage = restService
|
||||||
|
@ -2520,7 +2520,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
||||||
assertFalse(ccDataPage.content.isEmpty());
|
assertFalse(ccDataPage.content.isEmpty());
|
||||||
final ClientConnectionData clientConnectionData = ccDataPage.content.get(0);
|
final ClientConnectionData clientConnectionData = ccDataPage.content.get(0);
|
||||||
assertNotNull(clientConnectionData);
|
assertNotNull(clientConnectionData);
|
||||||
assertEquals("CLOSED", clientConnectionData.clientConnection.status.toString());
|
assertEquals("DISABLED", clientConnectionData.clientConnection.status.toString());
|
||||||
|
|
||||||
connectionDatacall = restService
|
connectionDatacall = restService
|
||||||
.getBuilder(GetFinishedExamClientConnectionPage.class)
|
.getBuilder(GetFinishedExamClientConnectionPage.class)
|
||||||
|
@ -2552,9 +2552,9 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
|
||||||
@Order(18)
|
@Order(18)
|
||||||
// *************************************
|
// *************************************
|
||||||
// Use Case 18: Login as examAdmin2 and get dependencies of examAdmin2
|
// Use Case 18: Login as examAdmin2 and get dependencies of examAdmin2
|
||||||
// - Get all dependencies and check correctnes.
|
// - Get all dependencies and check correctness.
|
||||||
// - Get all dependencies including only Exam Configuration and check correctnes.
|
// - Get all dependencies including only Exam Configuration and check correctness.
|
||||||
// - Get all dependencies including only ClientConnection and check correctnes.
|
// - Get all dependencies including only ClientConnection and check correctness.
|
||||||
public void testUsecase18_UserDependencies() throws IOException {
|
public void testUsecase18_UserDependencies() throws IOException {
|
||||||
final RestServiceImpl restService = createRestServiceForUser(
|
final RestServiceImpl restService = createRestServiceForUser(
|
||||||
"examAdmin2",
|
"examAdmin2",
|
||||||
|
|
Loading…
Reference in a new issue