SEBSP-119 and SEBSP-111

This commit is contained in:
anhefti 2024-05-16 10:50:36 +02:00
parent 3501c5de05
commit 1ae00cc4ab
5 changed files with 94 additions and 126 deletions

View file

@ -147,8 +147,8 @@ public final class UserMod implements UserAccount {
this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE); this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE);
this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE); this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE);
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME); this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
this.isLocalAccount = BooleanUtils.isNotFalse(postAttrMapper.getBoolean(USER.ATTR_LOCAL_ACCOUNT)); this.isLocalAccount = BooleanUtils.isNotFalse(postAttrMapper.getBooleanObject(USER.ATTR_LOCAL_ACCOUNT));
this.hasDirectLogin = BooleanUtils.isNotFalse(postAttrMapper.getBoolean(USER.ATTR_DIRECT_LOGIN)); this.hasDirectLogin = BooleanUtils.isNotFalse(postAttrMapper.getBooleanObject(USER.ATTR_DIRECT_LOGIN));
} }
@Override @Override

View file

@ -239,10 +239,12 @@ public class UserDAOImpl implements UserDAO {
checkUniqueUsername(userMod); checkUniqueUsername(userMod);
checkUniqueMailAddress(userMod); checkUniqueMailAddress(userMod);
final String uuid = userMod.uuid != null ? userMod.uuid : UUID.randomUUID().toString();
final UserRecord recordToSave = new UserRecord( final UserRecord recordToSave = new UserRecord(
null, null,
userMod.institutionId, userMod.institutionId,
UUID.randomUUID().toString(), uuid,
DateTime.now(DateTimeZone.UTC), DateTime.now(DateTimeZone.UTC),
userMod.name, userMod.name,
userMod.surname, userMod.surname,

View file

@ -28,8 +28,8 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
private static final Logger log = LoggerFactory.getLogger(MoodlePluginFullIntegration.class); private static final Logger log = LoggerFactory.getLogger(MoodlePluginFullIntegration.class);
private static final String FUNCTION_NAME_SEBSERVER_CONNECTION = "sebserver_connection"; private static final String FUNCTION_NAME_SEBSERVER_CONNECTION = "quizaccess_sebserver_connection";
private static final String FUNCTION_NAME_SEBSERVER_CONNECTION_DELETE = "sebserver_connection_delete"; private static final String FUNCTION_NAME_SEBSERVER_CONNECTION_DELETE = "quizaccess_sebserver_connection_delete";
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final MoodleRestTemplateFactory restTemplateFactory; private final MoodleRestTemplateFactory restTemplateFactory;
@ -82,9 +82,6 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
if (StringUtils.isBlank( data.access_token)) { if (StringUtils.isBlank( data.access_token)) {
throw new APIMessage.FieldValidationException("lmsFullIntegration:access_token", "access_token is mandatory"); throw new APIMessage.FieldValidationException("lmsFullIntegration:access_token", "access_token is mandatory");
} }
// if (data.exam_templates.isEmpty()) {
// throw new APIMessage.FieldValidationException("lmsFullIntegration:exam_templates", "exam_templates is mandatory");
// }
// apply // apply
final LmsSetup lmsSetup = this.restTemplateFactory.getApiTemplateDataSupplier().getLmsSetup(); final LmsSetup lmsSetup = this.restTemplateFactory.getApiTemplateDataSupplier().getLmsSetup();

View file

@ -84,30 +84,13 @@ class ScreenProctoringAPIBinding {
String USERSYNC_SEBSERVER_ENDPOINT = USER_ACCOUNT_ENDPOINT + "usersync/sebserver"; String USERSYNC_SEBSERVER_ENDPOINT = USER_ACCOUNT_ENDPOINT + "usersync/sebserver";
String ENTITY_PRIVILEGES_ENDPOINT = USER_ACCOUNT_ENDPOINT + "entityprivilege"; String ENTITY_PRIVILEGES_ENDPOINT = USER_ACCOUNT_ENDPOINT + "entityprivilege";
String EXAM_ENDPOINT = "/admin-api/v1/exam"; String EXAM_ENDPOINT = "/admin-api/v1/exam";
String EXAM_DELETE_REQUEST_ENDPOINT = "/request";
String SEB_ACCESS_ENDPOINT = "/admin-api/v1/clientaccess"; String SEB_ACCESS_ENDPOINT = "/admin-api/v1/clientaccess";
String GROUP_ENDPOINT = "/admin-api/v1/group"; String GROUP_ENDPOINT = "/admin-api/v1/group";
String SESSION_ENDPOINT = "/admin-api/v1/session"; String SESSION_ENDPOINT = "/admin-api/v1/session";
String ACTIVE_PATH_SEGMENT = "/active"; String ACTIVE_PATH_SEGMENT = "/active";
String INACTIVE_PATH_SEGMENT = "/inactive"; String INACTIVE_PATH_SEGMENT = "/inactive";
interface PRIVILEGE_FLAGS {
String READ = "r";
String MODIFY = "m";
String WRITE = "w";
}
/** The screen proctoring service user-account API attribute names */
interface USER {
String ATTR_UUID = "uuid";
String ATTR_NAME = "name";
String ATTR_SURNAME = "surname";
String ATTR_USERNAME = "username";
String ATTR_PASSWORD = "newPassword";
String ATTR_CONFIRM_PASSWORD = "confirmNewPassword";
String ATTR_LANGUAGE = "language";
String ATTR_TIMEZONE = "timeZone";
String ATTR_ROLES = "roles";
}
interface ENTITY_PRIVILEGE { interface ENTITY_PRIVILEGE {
String ATTR_ENTITY_TYPE = "entityType"; String ATTR_ENTITY_TYPE = "entityType";
@ -129,12 +112,14 @@ class ScreenProctoringAPIBinding {
/** The screen proctoring service group API attribute names */ /** The screen proctoring service group API attribute names */
interface EXAM { interface EXAM {
String ATTR_UUID = "uuid"; String ATTR_UUID = "uuid";
String ATTR_SEB_SERVER_ID = "sebserverId";
String ATTR_NAME = "name"; String ATTR_NAME = "name";
String ATTR_DESCRIPTION = "description"; String ATTR_DESCRIPTION = "description";
String ATTR_URL = "url"; String ATTR_URL = "url";
String ATTR_TYPE = "type"; String ATTR_TYPE = "type";
String ATTR_START_TIME = "startTime"; String ATTR_START_TIME = "startTime";
String ATTR_END_TIME = "endTime"; String ATTR_END_TIME = "endTime";
String ATTR_USER_IDS = "userUUIDs";
} }
/** The screen proctoring service seb-group API attribute names */ /** The screen proctoring service seb-group API attribute names */
@ -170,6 +155,8 @@ class ScreenProctoringAPIBinding {
final Long startTime; final Long startTime;
@JsonProperty(EXAM.ATTR_END_TIME) @JsonProperty(EXAM.ATTR_END_TIME)
final Long endTime; final Long endTime;
@JsonProperty(EXAM.ATTR_USER_IDS)
final Collection<String> userIds;
public ExamUpdate( public ExamUpdate(
final String name, final String name,
@ -177,7 +164,8 @@ class ScreenProctoringAPIBinding {
final String url, final String url,
final String type, final String type,
final Long startTime, final Long startTime,
final Long endTime) { final Long endTime,
final Collection<String> userIds) {
this.name = name; this.name = name;
this.description = description; this.description = description;
@ -185,6 +173,7 @@ class ScreenProctoringAPIBinding {
this.type = type; this.type = type;
this.startTime = startTime; this.startTime = startTime;
this.endTime = endTime; this.endTime = endTime;
this.userIds = userIds;
} }
} }
} }
@ -308,7 +297,11 @@ class ScreenProctoringAPIBinding {
final SPSData spsData = this.getSPSData(exam.id); final SPSData spsData = this.getSPSData(exam.id);
// re-activate all needed entities on SPS side // re-activate all needed entities on SPS side
activation(exam, SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, true, apiTemplate); if (exam.status == Exam.ExamStatus.RUNNING) {
activation(exam, SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, true, apiTemplate);
activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, true, apiTemplate);
}
synchronizeUserAccounts(exam);
// mark successfully activated on SPS side // mark successfully activated on SPS side
this.additionalAttributesDAO.saveAdditionalAttribute( this.additionalAttributesDAO.saveAdditionalAttribute(
@ -321,15 +314,13 @@ class ScreenProctoringAPIBinding {
} }
final SPSData spsData = new SPSData(); final SPSData spsData = new SPSData();
log.info( log.info(
"SPS Exam for SEB Server Exam: {} don't exists yet, create necessary structures on SPS", "SPS Exam for SEB Server Exam: {} don't exists yet, create necessary structures on SPS",
exam.externalId); exam.externalId);
exam.supporter.forEach(userUUID -> synchronizeUserAccount(userUUID, apiTemplate)); synchronizeUserAccounts(exam);
createSEBAccess(exam, apiTemplate, spsData); createSEBAccess(exam, apiTemplate, spsData);
createExam(exam, apiTemplate, spsData); createExam(exam, apiTemplate, spsData);
exam.supporter.forEach(userUUID -> createExamReadPrivilege(userUUID, spsData.spsExamUUID, apiTemplate));
final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData); final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData);
// store encrypted spsData // store encrypted spsData
@ -381,6 +372,9 @@ class ScreenProctoringAPIBinding {
final SPSData spsData = this.getSPSData(exam.id); final SPSData spsData = this.getSPSData(exam.id);
exam.supporter.forEach(userUUID -> synchronizeUserAccount(userUUID, apiTemplate)); exam.supporter.forEach(userUUID -> synchronizeUserAccount(userUUID, apiTemplate));
if (exam.owner != null) {
synchronizeUserAccount(exam.owner, apiTemplate);
}
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to synchronize user accounts with SPS for exam: {}", exam); log.error("Failed to synchronize user accounts with SPS for exam: {}", exam);
@ -413,11 +407,10 @@ class ScreenProctoringAPIBinding {
/** 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
* *
* @param exam The exam * @param exam The exam*/
* @return Result refer to the exam or to an error when happened */ void updateExam(final Exam exam) {
Result<Exam> updateExam(final Exam exam) {
return Result.tryCatch(() -> {
try {
final SPSData spsData = this.getSPSData(exam.id); final SPSData spsData = this.getSPSData(exam.id);
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id); final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
@ -428,13 +421,19 @@ class ScreenProctoringAPIBinding {
.build() .build()
.toUriString(); .toUriString();
final List<String> userIds = new ArrayList<>(exam.supporter);
if (exam.owner != null) {
userIds.add(exam.owner);
}
final ExamUpdate examUpdate = new ExamUpdate( final ExamUpdate examUpdate = new ExamUpdate(
exam.name, exam.name,
exam.getDescription(), exam.getDescription(),
exam.getStartURL(), exam.getStartURL(),
exam.getType().name(), exam.getType().name(),
exam.startTime != null ? exam.startTime.getMillis() : null, exam.startTime != null ? exam.startTime.getMillis() : null,
exam.endTime != null ? exam.endTime.getMillis() : null); exam.endTime != null ? exam.endTime.getMillis() : null,
userIds);
final String jsonExamUpdate = this.jsonMapper.writeValueAsString(examUpdate); final String jsonExamUpdate = this.jsonMapper.writeValueAsString(examUpdate);
@ -447,8 +446,9 @@ class ScreenProctoringAPIBinding {
log.error("Failed to update SPS exam data: {}", exchange); log.error("Failed to update SPS exam data: {}", exchange);
} }
return exam; } catch (Exception e) {
}); log.error("Failed to update exam on SPS service for exam: {}", exam, e);
}
} }
/** This is called when an exam finishes and deactivates the Exam, SEB Client Access and the ad-hoc User-Account /** This is called when an exam finishes and deactivates the Exam, SEB Client Access and the ad-hoc User-Account
@ -482,19 +482,19 @@ class ScreenProctoringAPIBinding {
/** This is called on exam delete and deletes the SEB Client Access and the ad-hoc User-Account /** This is called on exam delete and deletes the SEB Client Access and the ad-hoc User-Account
* on Screen Proctoring Service side. * on Screen Proctoring Service side.
* Also sends a exam delete request where Exam on SPS gets deleted if there are no session data for the exam
* *
* @param exam The exam * @param exam The exam
* @return Result refer to the exam or to an error when happened */ * @return Result refer to the exam or to an error when happened */
Result<Exam> deleteScreenProctoring(final Exam exam) { Exam deleteScreenProctoring(final Exam exam) {
try {
return Result.tryCatch(() -> {
if (!BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) { if (!BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) {
return exam; return exam;
} }
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Delete screen proctoring exam, groups and access on SPS for exam: {}", exam); log.debug("Deactivate exam and groups on SPS site and send deletion request for exam {}", exam);
} }
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id); final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
@ -502,6 +502,20 @@ class ScreenProctoringAPIBinding {
deletion(SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, apiTemplate); deletion(SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, apiTemplate);
activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, false, apiTemplate); activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, false, apiTemplate);
// exam delete request on SPS
final String uri = UriComponentsBuilder
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
.path(SPS_API.EXAM_ENDPOINT)
.pathSegment(spsData.spsExamUUID)
.pathSegment(SPS_API.EXAM_DELETE_REQUEST_ENDPOINT)
.build()
.toUriString();
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.DELETE);
if (exchange.getStatusCode() != HttpStatus.OK) {
log.error("Failed to request delete on SPS for Exam: {} with response: {}", exam, exchange);
}
// mark successfully dispose on SPS side // mark successfully dispose on SPS side
this.additionalAttributesDAO.saveAdditionalAttribute( this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.EXAM, EntityType.EXAM,
@ -509,8 +523,11 @@ class ScreenProctoringAPIBinding {
SPSData.ATTR_SPS_ACTIVE, SPSData.ATTR_SPS_ACTIVE,
Constants.FALSE_STRING); Constants.FALSE_STRING);
return exam;
}); } catch (final Exception e) {
log.warn("Failed to apply SPS deletion of exam: {} error: {}", exam, e.getMessage());
}
return exam;
} }
Result<ScreenProctoringGroup> createGroup( Result<ScreenProctoringGroup> createGroup(
@ -587,18 +604,6 @@ class ScreenProctoringAPIBinding {
} }
} }
void createExamReadPrivileges(final Exam exam) {
try {
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
final SPSData spsData = this.getSPSData(exam.id);
exam.supporter.forEach(userUUID -> createExamReadPrivilege(userUUID, spsData.spsExamUUID, apiTemplate));
} catch (final Exception e) {
log.error("Failed to synchronize user accounts exam privileges with SPS for exam: {}", exam);
}
}
private void synchronizeUserAccount( private void synchronizeUserAccount(
final String userUUID, final String userUUID,
final ScreenProctoringServiceOAuthTemplate apiTemplate) { final ScreenProctoringServiceOAuthTemplate apiTemplate) {
@ -641,6 +646,11 @@ class ScreenProctoringAPIBinding {
activityURI, HttpMethod.POST, jsonBody, apiTemplate.getHeaders()); activityURI, HttpMethod.POST, jsonBody, apiTemplate.getHeaders());
if (activityRequest.getStatusCode() != HttpStatus.OK) { if (activityRequest.getStatusCode() != HttpStatus.OK) {
final String body = activityRequest.getBody();
if (body != null && body.contains("Activation argument mismatch")) {
return;
}
log.warn("Failed to synchronize activity for user account on SPS: {}", activityRequest); log.warn("Failed to synchronize activity for user account on SPS: {}", activityRequest);
} else { } else {
log.info("Successfully synchronize activity for user account on SPS for user: {}", userUUID); log.info("Successfully synchronize activity for user account on SPS for user: {}", userUUID);
@ -675,51 +685,6 @@ class ScreenProctoringAPIBinding {
spsUserRoles); spsUserRoles);
} }
private void createExamReadPrivilege(
final String userUUID,
final String examUUID,
final ScreenProctoringServiceOAuthTemplate apiTemplate) {
try {
final UserInfo userInfo = this.userDAO
.byModelId(userUUID)
.getOrThrow();
final String uri = UriComponentsBuilder
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
.path(SPS_API.ENTITY_PRIVILEGES_ENDPOINT)
.build()
.toUriString();
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add(SPS_API.ENTITY_PRIVILEGE.ATTR_ENTITY_TYPE, EntityType.EXAM.name());
params.add(SPS_API.ENTITY_PRIVILEGE.ATTR_ENTITY_ID, examUUID);
params.add(SPS_API.ENTITY_PRIVILEGE.ATTR_USERNAME, userInfo.username);
params.add(SPS_API.ENTITY_PRIVILEGE.ATTR_PRIVILEGES, SPS_API.PRIVILEGE_FLAGS.READ);
final String paramsFormEncoded = Utils.toAppFormUrlEncodedBody(params);
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
if (exchange.getStatusCode() != HttpStatus.OK) {
log.warn(
"Failed to apply exam read privilege on SPS side for exam: {} and user: {}",
examUUID,
userUUID);
} else {
log.info(
"Successfully apply exam read privilege on SPS side for exam: {} and user: {}",
examUUID,
userUUID);
}
} catch (final Exception e) {
log.error(
"Failed to apply exam read privilege on SPS side for exam: {} and user: {} error: {}",
examUUID,
userUUID,
e.getMessage());
}
}
private Collection<ScreenProctoringGroup> initializeGroups( private Collection<ScreenProctoringGroup> initializeGroups(
final Exam exam, final Exam exam,
final ScreenProctoringServiceOAuthTemplate apiTemplate, final ScreenProctoringServiceOAuthTemplate apiTemplate,
@ -815,6 +780,11 @@ class ScreenProctoringAPIBinding {
try { try {
final List<String> userIds = new ArrayList<>(exam.supporter);
if (exam.owner != null) {
userIds.add(exam.owner);
}
final String uri = UriComponentsBuilder final String uri = UriComponentsBuilder
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL()) .fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
.path(SPS_API.EXAM_ENDPOINT) .path(SPS_API.EXAM_ENDPOINT)
@ -824,6 +794,9 @@ class ScreenProctoringAPIBinding {
params.add(SPS_API.EXAM.ATTR_NAME, exam.name); params.add(SPS_API.EXAM.ATTR_NAME, exam.name);
params.add(SPS_API.EXAM.ATTR_DESCRIPTION, exam.getDescription()); params.add(SPS_API.EXAM.ATTR_DESCRIPTION, exam.getDescription());
params.add(SPS_API.EXAM.ATTR_URL, exam.getStartURL()); params.add(SPS_API.EXAM.ATTR_URL, exam.getStartURL());
if (!userIds.isEmpty()) {
params.add(SPS_API.EXAM.ATTR_USER_IDS, StringUtils.join(userIds, Constants.LIST_SEPARATOR));
}
params.add(SPS_API.EXAM.ATTR_TYPE, exam.getType().name()); params.add(SPS_API.EXAM.ATTR_TYPE, exam.getType().name());
params.add(SPS_API.EXAM.ATTR_START_TIME, String.valueOf(exam.startTime.getMillis())); params.add(SPS_API.EXAM.ATTR_START_TIME, String.valueOf(exam.startTime.getMillis()));
@ -834,7 +807,10 @@ class ScreenProctoringAPIBinding {
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST); final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
if (exchange.getStatusCode() != HttpStatus.OK) { if (exchange.getStatusCode() != HttpStatus.OK) {
log.error("Failed to update SPS exam data: {}", exchange); throw new RuntimeException("Error response from Screen Proctoring Service: "
+ exchange.getStatusCodeValue()
+ " "
+ exchange.getBody());
} }
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody()); final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
@ -890,7 +866,6 @@ class ScreenProctoringAPIBinding {
rollbackOnSPS(exam, spsData, apiTemplate); rollbackOnSPS(exam, spsData, apiTemplate);
throw new RuntimeException("Failed to apply screen proctoring:", e); throw new RuntimeException("Failed to apply screen proctoring:", e);
} }
} }
private void activation( private void activation(
@ -994,7 +969,7 @@ class ScreenProctoringAPIBinding {
log.debug("Create new ScreenProctoringServiceOAuthTemplate for exam: {}", examId); log.debug("Create new ScreenProctoringServiceOAuthTemplate for exam: {}", examId);
} }
WebserviceInfo.ScreenProctoringServiceBundle bundle = this.webserviceInfo final WebserviceInfo.ScreenProctoringServiceBundle bundle = this.webserviceInfo
.getScreenProctoringServiceBundle(); .getScreenProctoringServiceBundle();
this.testConnection(bundle).getOrThrow(); this.testConnection(bundle).getOrThrow();
@ -1017,9 +992,6 @@ class ScreenProctoringAPIBinding {
private final SPSAPIAccessData spsAPIAccessData; private final SPSAPIAccessData spsAPIAccessData;
private final CircuitBreaker<ResponseEntity<String>> circuitBreaker; private final CircuitBreaker<ResponseEntity<String>> circuitBreaker;
private final ResourceOwnerPasswordResourceDetails resource;
private final ClientCredentials clientCredentials;
private final ClientCredentials userCredentials;
private final OAuth2RestTemplate restTemplate; private final OAuth2RestTemplate restTemplate;
ScreenProctoringServiceOAuthTemplate( ScreenProctoringServiceOAuthTemplate(
@ -1032,34 +1004,34 @@ class ScreenProctoringAPIBinding {
10 * Constants.SECOND_IN_MILLIS, 10 * Constants.SECOND_IN_MILLIS,
10 * Constants.SECOND_IN_MILLIS); 10 * Constants.SECOND_IN_MILLIS);
this.clientCredentials = new ClientCredentials( ClientCredentials clientCredentials = new ClientCredentials(
spsAPIAccessData.getSpsAPIKey(), spsAPIAccessData.getSpsAPIKey(),
spsAPIAccessData.getSpsAPISecret()); spsAPIAccessData.getSpsAPISecret());
CharSequence decryptedSecret = sebScreenProctoringService.cryptor CharSequence decryptedSecret = sebScreenProctoringService.cryptor
.decrypt(this.clientCredentials.secret) .decrypt(clientCredentials.secret)
.getOrThrow(); .getOrThrow();
this.resource = new ResourceOwnerPasswordResourceDetails(); final ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
this.resource.setAccessTokenUri(spsAPIAccessData.getSpsServiceURL() + SPS_API.TOKEN_ENDPOINT); resource.setAccessTokenUri(spsAPIAccessData.getSpsServiceURL() + SPS_API.TOKEN_ENDPOINT);
this.resource.setClientId(this.clientCredentials.clientIdAsString()); resource.setClientId(clientCredentials.clientIdAsString());
this.resource.setClientSecret(decryptedSecret.toString()); resource.setClientSecret(decryptedSecret.toString());
this.resource.setGrantType(GRANT_TYPE); resource.setGrantType(GRANT_TYPE);
this.resource.setScope(SCOPES); resource.setScope(SCOPES);
this.userCredentials = new ClientCredentials( final ClientCredentials userCredentials = new ClientCredentials(
spsAPIAccessData.getSpsAccountId(), spsAPIAccessData.getSpsAccountId(),
spsAPIAccessData.getSpsAccountPassword()); spsAPIAccessData.getSpsAccountPassword());
decryptedSecret = sebScreenProctoringService.cryptor decryptedSecret = sebScreenProctoringService.cryptor
.decrypt(this.userCredentials.secret) .decrypt(userCredentials.secret)
.getOrThrow(); .getOrThrow();
this.resource.setUsername(this.userCredentials.clientIdAsString()); resource.setUsername(userCredentials.clientIdAsString());
this.resource.setPassword(decryptedSecret.toString()); resource.setPassword(decryptedSecret.toString());
final SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); final SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false); requestFactory.setOutputStreaming(false);
final OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(this.resource); final OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resource);
oAuth2RestTemplate.setRequestFactory(requestFactory); oAuth2RestTemplate.setRequestFactory(requestFactory);
this.restTemplate = oAuth2RestTemplate; this.restTemplate = oAuth2RestTemplate;
} }

View file

@ -184,7 +184,6 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
exam, exam,
error)) error))
.getOrThrow() .getOrThrow()
.stream()
.forEach(newGroup -> createNewLocalGroup(exam, newGroup)); .forEach(newGroup -> createNewLocalGroup(exam, newGroup));
this.examDAO.markUpdate(exam.id); this.examDAO.markUpdate(exam.id);
@ -225,9 +224,8 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
log.debug("Update exam data on screen proctoring service for exam: {}", exam); log.debug("Update exam data on screen proctoring service for exam: {}", exam);
} }
this.screenProctoringAPIBinding.updateExam(exam); this.notifyExamSaved(exam);
return exam; return exam;
}); });
} }
@ -239,7 +237,6 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
.allIdsOfRunningWithScreenProctoringEnabled() .allIdsOfRunningWithScreenProctoringEnabled()
.flatMap(this.clientConnectionDAO::getAllForScreenProctoringUpdate) .flatMap(this.clientConnectionDAO::getAllForScreenProctoringUpdate)
.getOrThrow() .getOrThrow()
.stream()
.forEach(this::applyScreenProctoringSession); .forEach(this::applyScreenProctoringSession);
} catch (final Exception e) { } catch (final Exception e) {
@ -257,7 +254,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
} }
this.screenProctoringAPIBinding.synchronizeUserAccounts(exam); this.screenProctoringAPIBinding.synchronizeUserAccounts(exam);
this.screenProctoringAPIBinding.createExamReadPrivileges(exam); this.screenProctoringAPIBinding.updateExam(exam);
} }
@Override @Override
@ -445,7 +442,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
private Result<Exam> deleteForExam(final Long examId) { private Result<Exam> deleteForExam(final Long examId) {
return this.examDAO return this.examDAO
.byPK(examId) .byPK(examId)
.flatMap(this.screenProctoringAPIBinding::deleteScreenProctoring) .map(this.screenProctoringAPIBinding::deleteScreenProctoring)
.map(this::cleanupAllLocalGroups) .map(this::cleanupAllLocalGroups)
.onError(error -> log.error("Failed to delete SPS integration for exam: {}", examId, error)); .onError(error -> log.error("Failed to delete SPS integration for exam: {}", examId, error));
} }