SEBSERV-417 and SEBSP-111
This commit is contained in:
parent
c161e3c5ef
commit
8155d155c0
7 changed files with 58 additions and 89 deletions
|
@ -178,9 +178,9 @@ public final class API {
|
|||
public static final String LMS_FULL_INTEGRATION_EXAM_TEMPLATE_ID = "exam_template_id";
|
||||
public static final String LMS_FULL_INTEGRATION_QUIT_PASSWORD = "quit_password";
|
||||
public static final String LMS_FULL_INTEGRATION_QUIT_LINK = "quit_link";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_ID = "userid_id";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_NAME = "userid_username ";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_EMAIL = "userid_email";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_ID = "user_id";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_NAME = "user_username";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_EMAIL = "user_email";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_FIRST_NAME = "user_firstname";
|
||||
public static final String LMS_FULL_INTEGRATION_USER_LAST_NAME = "user_lastname";
|
||||
|
||||
|
|
|
@ -288,6 +288,8 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
}
|
||||
|
||||
final TokenLoginInfo loginInfo = response.getBody();
|
||||
this.resource.setUsername(loginInfo.username);
|
||||
this.resource.setPassword(loginInfo.userUUID);
|
||||
this.restTemplate.getOAuth2ClientContext().setAccessToken(loginInfo.login);
|
||||
|
||||
loginForward = loginInfo.login_forward;
|
||||
|
|
|
@ -27,11 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationServi
|
|||
public interface TeacherAccountService {
|
||||
|
||||
/** Creates an Ad-Hoc Teacher account for a given existing Exam.
|
||||
* This also checks if such an account already exists and if so,
|
||||
* it uses that and activates it if not already active
|
||||
*
|
||||
* @param exam The Exam instance
|
||||
* @param adHocAccountData The account data for new Ad-Hoc account
|
||||
|
@ -38,7 +36,11 @@ public interface TeacherAccountService {
|
|||
default String getTeacherAccountIdentifier(
|
||||
final Exam exam,
|
||||
final FullLmsIntegrationService.AdHocAccountData adHocAccountData) {
|
||||
return getTeacherAccountIdentifier(exam.getModelId(), adHocAccountData.userId);
|
||||
|
||||
return getTeacherAccountIdentifier(
|
||||
exam.getModelId(),
|
||||
String.valueOf(exam.lmsSetupId),
|
||||
adHocAccountData.userId);
|
||||
}
|
||||
|
||||
/** Get the identifier for certain Teacher account for specified Exam.
|
||||
|
@ -47,7 +49,7 @@ public interface TeacherAccountService {
|
|||
* @param userId the account id
|
||||
* @return account identifier
|
||||
*/
|
||||
String getTeacherAccountIdentifier(String examId, String userId);
|
||||
String getTeacherAccountIdentifier(String examId, String lmsId, String userId);
|
||||
|
||||
/** Deactivates a certain ad-hoc Teacher account
|
||||
* Usually called when an exam is deleted. Checks if Teacher account for exam
|
||||
|
|
|
@ -77,12 +77,16 @@ public class TeacherAccountServiceImpl implements TeacherAccountService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getTeacherAccountIdentifier(final String examId, final String userId) {
|
||||
if (examId == null || userId == null) {
|
||||
public String getTeacherAccountIdentifier(
|
||||
final String examId,
|
||||
final String lmsId,
|
||||
final String userId) {
|
||||
|
||||
if (examId == null || lmsId == null || userId == null) {
|
||||
throw new RuntimeException("examId and/or userId cannot be null");
|
||||
}
|
||||
|
||||
return userId;
|
||||
return examId + Constants.UNDERLINE + lmsId + Constants.UNDERLINE + userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -148,7 +152,6 @@ public class TeacherAccountServiceImpl implements TeacherAccountService {
|
|||
.byModelId(getTeacherAccountIdentifier(exam, adHocAccountData))
|
||||
.onErrorDo(error -> handleAccountDoesNotExistYet(createIfNotExists, exam, adHocAccountData))
|
||||
.map(account -> applySupporter(account, exam))
|
||||
.map(account -> synchronizeSPSUserForExam(account, exam.id))
|
||||
.map(account -> this.createOneTimeToken(account, exam.id));
|
||||
}
|
||||
|
||||
|
@ -191,7 +194,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService {
|
|||
key,
|
||||
"MONITOR_EXAM_FROM_LIST");
|
||||
|
||||
return new TokenLoginInfo(user.username, user.uuid, loginForward, token);
|
||||
return new TokenLoginInfo(user.username, claims.getSubject(), loginForward, token);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -231,6 +234,7 @@ public class TeacherAccountServiceImpl implements TeacherAccountService {
|
|||
|
||||
final String subjectClaim = UUID.randomUUID().toString();
|
||||
userDAO.changePassword(account.uuid, subjectClaim);
|
||||
synchronizeSPSUserForExam(account, examId);
|
||||
|
||||
final Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(USER_CLAIM, account.uuid);
|
||||
|
|
|
@ -31,14 +31,10 @@ public interface FullLmsIntegrationService {
|
|||
|
||||
@EventListener
|
||||
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||
|
||||
//Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||
|
||||
@EventListener
|
||||
void notifyExamTemplateChange(final ExamTemplateChangeEvent event);
|
||||
@EventListener(ConnectionConfigurationChangeEvent.class)
|
||||
void notifyConnectionConfigurationChange(ConnectionConfigurationChangeEvent event);
|
||||
|
||||
@EventListener(ExamDeletionEvent.class)
|
||||
void notifyExamDeletion(ExamDeletionEvent event);
|
||||
|
||||
|
|
|
@ -332,9 +332,9 @@ class ScreenProctoringAPIBinding {
|
|||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.GET);
|
||||
|
||||
if (exchange.getStatusCode() != HttpStatus.NOT_FOUND) {
|
||||
if (exchange.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return false;
|
||||
} else if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
} else if (exchange.getStatusCode() == HttpStatus.OK) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to verify if Exam on SPS already exists: {}", exchange.getBody());
|
||||
|
@ -468,6 +468,10 @@ class ScreenProctoringAPIBinding {
|
|||
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
if (!this.isSPSActive(exam)) {
|
||||
return exam;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Deactivate active screen proctoring exam, groups and access on SPS for exam: {}", exam.name);
|
||||
}
|
||||
|
@ -629,56 +633,6 @@ class ScreenProctoringAPIBinding {
|
|||
|
||||
}
|
||||
|
||||
// /** This is called on exam delete and deletes the SEB Client Access and the ad-hoc User-Account
|
||||
// * 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
|
||||
// * @return Result refer to the exam or to an error when happened */
|
||||
// Exam deleteScreenProctoring(final Exam exam) {
|
||||
// try {
|
||||
//
|
||||
// if (!BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) {
|
||||
// return exam;
|
||||
// }
|
||||
//
|
||||
// if (log.isDebugEnabled()) {
|
||||
// log.debug("Deactivate exam and groups on SPS site and send deletion request for exam {}", exam);
|
||||
// }
|
||||
//
|
||||
// final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||
// final SPSData spsData = this.getSPSData(exam.id);
|
||||
// deletion(SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, 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
|
||||
// this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
// EntityType.EXAM,
|
||||
// exam.id,
|
||||
// SPSData.ATTR_SPS_ACTIVE,
|
||||
// Constants.FALSE_STRING);
|
||||
//
|
||||
//
|
||||
// } catch (final Exception e) {
|
||||
// log.warn("Failed to apply SPS deletion of exam: {} error: {}", exam, e.getMessage());
|
||||
// }
|
||||
// return exam;
|
||||
// }
|
||||
|
||||
Result<ScreenProctoringGroup> createGroup(
|
||||
final String spsExamUUID,
|
||||
final int groupNumber,
|
||||
|
@ -741,23 +695,14 @@ class ScreenProctoringAPIBinding {
|
|||
return token;
|
||||
}
|
||||
|
||||
// void activateExamOnSPS(final Exam exam, final boolean activate) {
|
||||
// try {
|
||||
// final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||
// final SPSData spsData = this.getSPSData(exam.id);
|
||||
//
|
||||
// activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsSEBAccessUUID, activate, apiTemplate);
|
||||
// activation(exam, SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, activate, apiTemplate);
|
||||
//
|
||||
// } catch (final Exception e) {
|
||||
// log.error("Failed to de/activate SEB Access on SPS for exam: {}", exam);
|
||||
// }
|
||||
// }
|
||||
|
||||
private void synchronizeUserAccount(
|
||||
final String userUUID,
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate) {
|
||||
|
||||
if (UserService.LMS_INTEGRATION_CLIENT_UUID.equals(userUUID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
final UserInfo userInfo = this.userDAO
|
||||
|
@ -919,7 +864,6 @@ class ScreenProctoringAPIBinding {
|
|||
});
|
||||
|
||||
final String spsGroupUUID = groupAttributes.get(SPS_API.GROUP.ATTR_UUID);
|
||||
|
||||
return new ScreenProctoringGroup(null, examId, spsGroupUUID, name, size, exchange.getBody());
|
||||
}
|
||||
|
||||
|
@ -1007,7 +951,33 @@ class ScreenProctoringAPIBinding {
|
|||
final String name = SEB_SERVER_SCREEN_PROCTORING_SEB_ACCESS_PREFIX + exam.externalId;
|
||||
final String description = "This SEB access was auto-generated by SEB Server";
|
||||
|
||||
final String uri = UriComponentsBuilder
|
||||
// first try to get existing one by name and link it if available
|
||||
String uri = UriComponentsBuilder
|
||||
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||
.path(SPS_API.SEB_ACCESS_ENDPOINT)
|
||||
.queryParam(SPS_API.SEB_ACCESS.ATTR_NAME, name)
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
final ResponseEntity<String> getResponse = apiTemplate.exchange(uri, HttpMethod.GET);
|
||||
if (getResponse.getStatusCode() == HttpStatus.OK) {
|
||||
try {
|
||||
final JsonNode requestJSON = this.jsonMapper.readTree(getResponse.getBody());
|
||||
final JsonNode content = requestJSON.get("content");
|
||||
if (content.isArray()) {
|
||||
final JsonNode sebConnection = content.get(0);
|
||||
spsData.spsSEBAccessUUID = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_UUID).textValue();
|
||||
spsData.spsSEBAccessName = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_NAME).textValue();
|
||||
spsData.spsSEBAccessPWD = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_SECRET).textValue();
|
||||
return;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to extract existing SEB Account from JSON: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise create new one and link it
|
||||
uri = UriComponentsBuilder
|
||||
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||
.path(SPS_API.SEB_ACCESS_ENDPOINT)
|
||||
.build()
|
||||
|
@ -1022,7 +992,6 @@ class ScreenProctoringAPIBinding {
|
|||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException("Failed to create SPS SEB access for exam: " + exam.externalId);
|
||||
}
|
||||
;
|
||||
|
||||
// store SEB access data for proctoring along with the exam
|
||||
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
|
||||
|
|
Loading…
Reference in a new issue