SEBSERV-417 and SEBSP-111
This commit is contained in:
parent
3a5129f796
commit
c161e3c5ef
13 changed files with 414 additions and 168 deletions
|
@ -20,6 +20,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServe
|
|||
public interface UserService {
|
||||
|
||||
String USERS_INSTITUTION_AS_DEFAULT = "USERS_INSTITUTION_AS_DEFAULT";
|
||||
String LMS_INTEGRATION_CLIENT_UUID = "LMS_INTEGRATION_CLIENT";
|
||||
String LMS_INTEGRATION_CLIENT_NAME = "lmsIntegrationClient";
|
||||
|
||||
/** Use this to get the current User within a request-response thread cycle.
|
||||
*
|
||||
|
|
|
@ -38,6 +38,7 @@ public class UserServiceImpl implements UserService {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
|
||||
|
||||
|
||||
public interface ExtractUserFromAuthenticationStrategy {
|
||||
SEBServerUser extract(Principal principal);
|
||||
}
|
||||
|
@ -137,7 +138,13 @@ public class UserServiceImpl implements UserService {
|
|||
if ("lmsClient".equals(name)) {
|
||||
return new SEBServerUser(
|
||||
-1L,
|
||||
new UserInfo("LMS_INTEGRATION_CLIENT", -1L, null, "lmsIntegrationClient", "lmsIntegrationClient", "lmsIntegrationClient", null,
|
||||
new UserInfo(
|
||||
LMS_INTEGRATION_CLIENT_UUID,
|
||||
-1L,
|
||||
null,
|
||||
LMS_INTEGRATION_CLIENT_NAME,
|
||||
LMS_INTEGRATION_CLIENT_NAME,
|
||||
LMS_INTEGRATION_CLIENT_NAME, null,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
|
|
|
@ -52,7 +52,12 @@ public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup, LmsSetup>, B
|
|||
* @return Result refers to the specified LMS Setup or to en error when happened */
|
||||
Result<LmsSetup> setIntegrationActive(Long lmsSetupId, boolean active);
|
||||
|
||||
boolean isIntegrationActive(Long lmsSetupId);
|
||||
|
||||
Result<Collection<Long>> idsOfActiveWithFullIntegration(Long institutionId);
|
||||
|
||||
Result<Collection<Long>> allIdsFullIntegration();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -317,6 +317,21 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
.onError(TransactionHandler::rollback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isIntegrationActive(final Long lmsSetupId) {
|
||||
try {
|
||||
return this.lmsSetupRecordMapper.countByExample()
|
||||
.where(LmsSetupRecordDynamicSqlSupport.id, isEqualTo(lmsSetupId))
|
||||
.and(integrationActive, isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute() > 0;
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to verify if full LMS integration is active: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isActive(final String modelId) {
|
||||
|
|
|
@ -32,7 +32,7 @@ public interface FullLmsIntegrationService {
|
|||
@EventListener
|
||||
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||
|
||||
Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||
//Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||
|
||||
@EventListener
|
||||
void notifyExamTemplateChange(final ExamTemplateChangeEvent event);
|
||||
|
|
|
@ -73,6 +73,6 @@ public interface SEBRestrictionService {
|
|||
@EventListener
|
||||
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||
|
||||
Result<LmsSetup> applyLMSSetupDeactivation(LmsSetup lmsSetup);
|
||||
Result<LmsSetup> releaseAllRestrictionsOf(LmsSetup lmsSetup);
|
||||
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
return Result.tryCatch(() -> {
|
||||
final LmsSetup lmsSetup = lmsSetupDAO.byPK(exam.lmsSetupId).getOrThrow();
|
||||
if (lmsSetup.lmsType.features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||
return this.applyExamData(exam, false);
|
||||
return this.applyExamData(exam, !exam.active);
|
||||
}
|
||||
|
||||
return exam;
|
||||
|
@ -183,17 +183,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.map(data -> reapplyExistingExams(data,lmsSetup))
|
||||
.onError(error -> log.warn("Failed to update LMS integration for: {} error {}", lmsSetup, error.getMessage()))
|
||||
.onSuccess(data -> log.debug("Successfully updated LMS integration for: {} data: {}", lmsSetup, data));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<LmsSetup> applyLMSSetupDeactivation(final LmsSetup lmsSetup) {
|
||||
if (!lmsSetup.getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||
return Result.of(lmsSetup);
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
} else if (event.activation == Activatable.ActivationAction.DEACTIVATE) {
|
||||
// remove all active exam data for involved exams before deactivate them
|
||||
this.examDAO
|
||||
.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||
|
@ -203,13 +193,10 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.map(e -> applyExamData(e, true))
|
||||
.onError(error -> log.warn("Failed delete teacher accounts for exam: {}", exam.name));
|
||||
});
|
||||
|
||||
// delete full integration on Moodle side before deactivate LMS Setup
|
||||
// delete full integration on Moodle side due to deactivation
|
||||
this.deleteFullLmsIntegration(lmsSetup.id)
|
||||
.getOrThrow();
|
||||
|
||||
return lmsSetup;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -302,6 +289,10 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!lmsSetupDAO.isIntegrationActive(lmsSetupId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
lmsAPITemplateCacheService.getLmsAPITemplate(lmsSetupId)
|
||||
.getOrThrow()
|
||||
.deleteConnectionDetails()
|
||||
|
|
|
@ -114,6 +114,7 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
|||
if (!lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (event.activation == Activatable.ActivationAction.ACTIVATE) {
|
||||
examDAO.allActiveForLMSSetup(Arrays.asList(lmsSetup.id))
|
||||
|
@ -125,6 +126,11 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
|||
log.warn("Failed to update SEB restriction for exam: {} error: {}", exam.name, e.getMessage());
|
||||
}
|
||||
});
|
||||
} else if (event.activation == Activatable.ActivationAction.DEACTIVATE) {
|
||||
releaseAllRestrictionsOf(lmsSetup)
|
||||
.onError(error -> log.warn(
|
||||
"Failed to remove all SEB Restrictions on LMS Setup deactivation: {}",
|
||||
error.getMessage()));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to update SEB restriction for re-activated exams: {}", e.getMessage());
|
||||
|
@ -132,8 +138,7 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Result<LmsSetup> applyLMSSetupDeactivation(final LmsSetup lmsSetup) {
|
||||
|
||||
public Result<LmsSetup> releaseAllRestrictionsOf(final LmsSetup lmsSetup) {
|
||||
return Result.tryCatch(() -> {
|
||||
// only relevant for LMS Setups with SEB restriction feature
|
||||
if (!lmsSetup.lmsType.features.contains(Features.SEB_RESTRICTION)) {
|
||||
|
@ -274,7 +279,6 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
|||
// create new ones if needed
|
||||
sebRestriction.additionalProperties
|
||||
.entrySet()
|
||||
.stream()
|
||||
.forEach(entry -> this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
|
@ -332,7 +336,7 @@ public class SEBRestrictionServiceImpl implements SEBRestrictionService {
|
|||
log.debug("ExamDeletionEvent received, process releaseSEBClientRestriction...");
|
||||
}
|
||||
|
||||
event.ids.stream().forEach(this::processExamDeletion);
|
||||
event.ids.forEach(this::processExamDeletion);
|
||||
}
|
||||
|
||||
private Result<Exam> processExamDeletion(final Long examId) {
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.util.Collection;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
|
@ -76,6 +78,9 @@ public interface ScreenProctoringService extends SessionUpdateTask {
|
|||
@EventListener(ExamDeletionEvent.class)
|
||||
void notifyExamDeletion(final ExamDeletionEvent event);
|
||||
|
||||
@EventListener
|
||||
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
|
||||
|
||||
/** This is used to update the exam equivalent on the screen proctoring service side
|
||||
* if screen proctoring is enabled for the specified exam.
|
||||
*
|
||||
|
@ -93,6 +98,7 @@ public interface ScreenProctoringService extends SessionUpdateTask {
|
|||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
void synchronizeSPSUser(final String userUUID);
|
||||
|
||||
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
void synchronizeSPSUserForExam(final Long examId);
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.SPSAPIAccessData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -111,6 +113,7 @@ class ScreenProctoringAPIBinding {
|
|||
|
||||
/** The screen proctoring service group API attribute names */
|
||||
interface EXAM {
|
||||
String ATTR_ID = "id";
|
||||
String ATTR_UUID = "uuid";
|
||||
String ATTR_SEB_SERVER_ID = "sebserverId";
|
||||
String ATTR_NAME = "name";
|
||||
|
@ -269,7 +272,7 @@ class ScreenProctoringAPIBinding {
|
|||
SPSData.class);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to get local SPSData for exam: {}", examId);
|
||||
log.warn("Failed to get local SPSData for exam: {}", examId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +293,9 @@ class ScreenProctoringAPIBinding {
|
|||
}
|
||||
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||
|
||||
|
||||
// if we have an exam where SPS was initialized before but deactivated meanwhile
|
||||
// reactivate on SPS site and synchronize
|
||||
if (exam.additionalAttributes.containsKey(SPSData.ATTR_SPS_ACTIVE)) {
|
||||
|
||||
log.info("SPS Exam for SEB Server Exam: {} already exists. Try to re-activate", exam.externalId);
|
||||
|
@ -298,51 +303,55 @@ class ScreenProctoringAPIBinding {
|
|||
final SPSData spsData = this.getSPSData(exam.id);
|
||||
// re-activate all needed entities on SPS side
|
||||
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);
|
||||
activateScreenProctoring(exam).getOrThrow();
|
||||
}
|
||||
|
||||
synchronizeUserAccounts(exam);
|
||||
|
||||
// mark successfully activated on SPS side
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACTIVE,
|
||||
Constants.TRUE_STRING);
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final SPSData spsData = new SPSData();
|
||||
log.info(
|
||||
"SPS Exam for SEB Server Exam: {} don't exists yet, create necessary structures on SPS",
|
||||
exam.externalId);
|
||||
// if we have a new Exam but Exam on SPS site for ExamUUID exists, reinitialize the exam and synchronize
|
||||
if (existsExamOnSPS(exam)) {
|
||||
return reinitializeScreenProctoring(exam);
|
||||
}
|
||||
|
||||
synchronizeUserAccounts(exam);
|
||||
createSEBAccess(exam, apiTemplate, spsData);
|
||||
createExam(exam, apiTemplate, spsData);
|
||||
final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData);
|
||||
|
||||
// store encrypted spsData
|
||||
final String spsDataJSON = this.jsonMapper.writeValueAsString(spsData);
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACCESS_DATA,
|
||||
this.cryptor.encrypt(spsDataJSON).getOrThrow().toString());
|
||||
|
||||
// mark successfully activated on SPS side
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACTIVE,
|
||||
Constants.TRUE_STRING);
|
||||
|
||||
return initializeGroups;
|
||||
// If this is a completely new exam with new SPS binding, initialize it
|
||||
return initializeScreenProctoring(exam, apiTemplate);
|
||||
});
|
||||
}
|
||||
|
||||
boolean existsExamOnSPS(final Exam exam) {
|
||||
try {
|
||||
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||
final String uri = UriComponentsBuilder
|
||||
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||
.path(SPS_API.EXAM_ENDPOINT)
|
||||
.pathSegment(createExamUUID(exam))
|
||||
.build().toUriString();
|
||||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.GET);
|
||||
|
||||
if (exchange.getStatusCode() != HttpStatus.NOT_FOUND) {
|
||||
return false;
|
||||
} else if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to verify if Exam on SPS already exists: {}", exchange.getBody());
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to verify if Exam exists already on SPS site: ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void synchronizeUserAccount(final String userUUID) {
|
||||
if (UserService.LMS_INTEGRATION_CLIENT_UUID.equals(userUUID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(null);
|
||||
|
@ -446,22 +455,21 @@ class ScreenProctoringAPIBinding {
|
|||
log.error("Failed to update SPS exam data: {}", exchange);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (final 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
|
||||
* on Screen Proctoring Service side.
|
||||
/** This is called when an exam finishes and deactivates the Exam, SEB Client Access on Screen Proctoring Service side.
|
||||
*
|
||||
* @param exam The exam
|
||||
* @return Result refer to the exam or to an error when happened */
|
||||
Result<Exam> disposeScreenProctoring(final Exam exam) {
|
||||
Result<Exam> deactivateScreenProctoring(final Exam exam) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Dispose active screen proctoring exam, groups and access on SPS for exam: {}", exam);
|
||||
log.debug("Deactivate active screen proctoring exam, groups and access on SPS for exam: {}", exam.name);
|
||||
}
|
||||
|
||||
final SPSData spsData = this.getSPSData(exam.id);
|
||||
|
@ -469,7 +477,7 @@ class ScreenProctoringAPIBinding {
|
|||
activation(exam, SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, false, apiTemplate);
|
||||
activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, false, apiTemplate);
|
||||
|
||||
// mark successfully dispose on SPS side
|
||||
// mark local for successfully dispose on SPS side
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
|
@ -480,56 +488,197 @@ 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 {
|
||||
Result<Exam> activateScreenProctoring(final Exam exam) {
|
||||
|
||||
if (!BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) {
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Activate screen proctoring exam, groups and access on SPS for exam: {}", exam.name);
|
||||
}
|
||||
|
||||
final SPSData spsData = this.getSPSData(exam.id);
|
||||
if (spsData == null) {
|
||||
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);
|
||||
activation(exam, SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, true, apiTemplate);
|
||||
activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, true, 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 local for successfully activated on SPS side
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACTIVE,
|
||||
Constants.FALSE_STRING);
|
||||
Constants.TRUE_STRING);
|
||||
|
||||
return exam;
|
||||
});
|
||||
}
|
||||
|
||||
private Collection<ScreenProctoringGroup> initializeScreenProctoring(
|
||||
final Exam exam,
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate) throws JsonProcessingException {
|
||||
|
||||
final SPSData spsData = new SPSData();
|
||||
log.info(
|
||||
"SPS Exam for SEB Server Exam: {} don't exists yet, create necessary structures on SPS",
|
||||
exam.externalId);
|
||||
|
||||
synchronizeUserAccounts(exam);
|
||||
createSEBAccess(exam, apiTemplate, spsData);
|
||||
createExam(exam, apiTemplate, spsData);
|
||||
final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData);
|
||||
|
||||
// store encrypted spsData
|
||||
final String spsDataJSON = this.jsonMapper.writeValueAsString(spsData);
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACCESS_DATA,
|
||||
this.cryptor.encrypt(spsDataJSON).getOrThrow().toString());
|
||||
|
||||
// mark successfully activated on SPS side
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACTIVE,
|
||||
Constants.TRUE_STRING);
|
||||
|
||||
return initializeGroups;
|
||||
}
|
||||
|
||||
Collection<ScreenProctoringGroup> reinitializeScreenProctoring(final Exam exam) {
|
||||
try {
|
||||
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||
|
||||
// get exam from SPS
|
||||
final String examUUID = createExamUUID(exam);
|
||||
final String uri = UriComponentsBuilder
|
||||
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||
.path(SPS_API.EXAM_ENDPOINT)
|
||||
.pathSegment(examUUID)
|
||||
.build().toUriString();
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.GET);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException("Failed to get Exam from SPS. local exam uuid: " + examUUID);
|
||||
}
|
||||
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
|
||||
final String spsExamId = requestJSON.get(SPS_API.EXAM.ATTR_ID).textValue();
|
||||
|
||||
|
||||
// check if Exam has SPSData, if not create and if check completeness
|
||||
SPSData spsData = this.getSPSData(exam.id);
|
||||
if (spsData == null) {
|
||||
spsData = new SPSData();
|
||||
}
|
||||
// create new SEB Account on SPS if needed
|
||||
if (spsData.spsSEBAccessUUID == null) {
|
||||
createSEBAccess(exam, apiTemplate, spsData);
|
||||
}
|
||||
|
||||
spsData.spsExamUUID = examUUID;
|
||||
// store encrypted spsData
|
||||
final String spsDataJSON = this.jsonMapper.writeValueAsString(spsData);
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.EXAM,
|
||||
exam.id,
|
||||
SPSData.ATTR_SPS_ACCESS_DATA,
|
||||
this.cryptor.encrypt(spsDataJSON).getOrThrow().toString());
|
||||
|
||||
// reactivate exam on SPS
|
||||
this.activateScreenProctoring(exam);
|
||||
|
||||
// recreate groups on SEB Server if needed
|
||||
try {
|
||||
final Collection<ScreenProctoringGroup> groups = new ArrayList<>();
|
||||
final String groupRequestURI = UriComponentsBuilder
|
||||
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||
.path(SPS_API.GROUP_ENDPOINT)
|
||||
.queryParam(Page.ATTR_PAGE_SIZE, 100)
|
||||
.queryParam(SPS_API.GROUP.ATTR_EXAM_ID, spsExamId)
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
final JsonNode groupsJSON = this.jsonMapper.readTree(exchange.getBody());
|
||||
final JsonNode pageContent = groupsJSON.get("content");
|
||||
if (pageContent.isArray()) {
|
||||
for (final JsonNode group : pageContent) {
|
||||
groups.add(new ScreenProctoringGroup(
|
||||
null,
|
||||
exam.id,
|
||||
group.get(SPS_API.GROUP.ATTR_UUID).textValue(),
|
||||
group.get(SPS_API.GROUP.ATTR_NAME).textValue(),
|
||||
0,
|
||||
null
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return groups;
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to get exam groups from SPS due to reinitialization: ", e);
|
||||
return initializeGroups(exam, apiTemplate, spsData);
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to apply SPS deletion of exam: {} error: {}", exam, e.getMessage());
|
||||
log.error("Failed to re-initialize Screen Proctoring: ", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return exam;
|
||||
|
||||
}
|
||||
|
||||
// /** 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,
|
||||
|
@ -583,7 +732,7 @@ class ScreenProctoringAPIBinding {
|
|||
params.add(SPS_API.SESSION.ATTR_CLIENT_VERSION, clientConnection.getClientVersion());
|
||||
final String paramsFormEncoded = Utils.toAppFormUrlEncodedBody(params);
|
||||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create SPS SEB session for SEB connection: " + token);
|
||||
|
@ -592,17 +741,18 @@ class ScreenProctoringAPIBinding {
|
|||
return token;
|
||||
}
|
||||
|
||||
void activateSEBAccessOnSPS(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.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, activate, apiTemplate);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to de/activate SEB Access on SPS for exam: {}", exam);
|
||||
}
|
||||
}
|
||||
// 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,
|
||||
|
@ -758,17 +908,17 @@ class ScreenProctoringAPIBinding {
|
|||
params.add(SPS_API.GROUP.ATTR_EXAM_ID, spsExamUUID);
|
||||
final String paramsFormEncoded = Utils.toAppFormUrlEncodedBody(params);
|
||||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException("Failed to create SPS SEB group for exam: " + spsExamUUID);
|
||||
}
|
||||
|
||||
final Map<String, String> userAttributes = this.jsonMapper.readValue(
|
||||
final Map<String, String> groupAttributes = this.jsonMapper.readValue(
|
||||
exchange.getBody(),
|
||||
new TypeReference<Map<String, String>>() {
|
||||
});
|
||||
|
||||
final String spsGroupUUID = userAttributes.get(SPS_API.GROUP.ATTR_UUID);
|
||||
final String spsGroupUUID = groupAttributes.get(SPS_API.GROUP.ATTR_UUID);
|
||||
|
||||
return new ScreenProctoringGroup(null, examId, spsGroupUUID, name, size, exchange.getBody());
|
||||
}
|
||||
|
@ -790,22 +940,11 @@ class ScreenProctoringAPIBinding {
|
|||
.path(SPS_API.EXAM_ENDPOINT)
|
||||
.build().toUriString();
|
||||
|
||||
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add(SPS_API.EXAM.ATTR_NAME, exam.name);
|
||||
params.add(SPS_API.EXAM.ATTR_DESCRIPTION, exam.getDescription());
|
||||
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_START_TIME, String.valueOf(exam.startTime.getMillis()));
|
||||
|
||||
if (exam.endTime != null) {
|
||||
params.add(SPS_API.EXAM.ATTR_END_TIME, String.valueOf(exam.endTime.getMillis()));
|
||||
}
|
||||
final String uuid = createExamUUID(exam);
|
||||
final MultiValueMap<String, String> params = createExamCreationParams(exam, uuid, userIds);
|
||||
final String paramsFormEncoded = Utils.toAppFormUrlEncodedBody(params);
|
||||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException("Error response from Screen Proctoring Service: "
|
||||
+ exchange.getStatusCodeValue()
|
||||
|
@ -814,7 +953,14 @@ class ScreenProctoringAPIBinding {
|
|||
}
|
||||
|
||||
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
|
||||
spsData.spsExamUUID = requestJSON.get(SPS_API.EXAM.ATTR_UUID).textValue();
|
||||
final String respondedUUID = requestJSON.get(SPS_API.EXAM.ATTR_UUID).textValue();
|
||||
if (!uuid.equals(respondedUUID)) {
|
||||
log.warn("Detected Exam ({}) generation UUID mismatch. propagated UUID: {} responded UUID: {}",
|
||||
exam.name,
|
||||
uuid,
|
||||
respondedUUID);
|
||||
}
|
||||
spsData.spsExamUUID = respondedUUID;
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error(
|
||||
|
@ -826,6 +972,32 @@ class ScreenProctoringAPIBinding {
|
|||
}
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> createExamCreationParams(
|
||||
final Exam exam,
|
||||
final String uuid,
|
||||
final List<String> userIds) {
|
||||
|
||||
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add(SPS_API.EXAM.ATTR_UUID, uuid);
|
||||
params.add(SPS_API.EXAM.ATTR_NAME, exam.name);
|
||||
params.add(SPS_API.EXAM.ATTR_DESCRIPTION, exam.getDescription());
|
||||
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_START_TIME, String.valueOf(exam.startTime.getMillis()));
|
||||
|
||||
if (exam.endTime != null) {
|
||||
params.add(SPS_API.EXAM.ATTR_END_TIME, String.valueOf(exam.endTime.getMillis()));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private String createExamUUID(final Exam exam) {
|
||||
return exam.externalId;
|
||||
}
|
||||
|
||||
private void createSEBAccess(
|
||||
final Exam exam,
|
||||
final ScreenProctoringServiceOAuthTemplate apiTemplate,
|
||||
|
@ -846,7 +1018,7 @@ class ScreenProctoringAPIBinding {
|
|||
params.add(SPS_API.SEB_ACCESS.ATTR_DESCRIPTION, description);
|
||||
final String paramsFormEncoded = Utils.toAppFormUrlEncodedBody(params);
|
||||
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded, HttpMethod.POST);
|
||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, paramsFormEncoded);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
throw new RuntimeException("Failed to create SPS SEB access for exam: " + exam.externalId);
|
||||
}
|
||||
|
@ -1099,10 +1271,9 @@ class ScreenProctoringAPIBinding {
|
|||
|
||||
ResponseEntity<String> exchange(
|
||||
final String url,
|
||||
final String body,
|
||||
final HttpMethod method) {
|
||||
final String body) {
|
||||
|
||||
return exchange(url, method, body, getHeaders());
|
||||
return exchange(url, HttpMethod.POST, body, getHeaders());
|
||||
}
|
||||
|
||||
HttpHeaders getHeadersJSONRequest() {
|
||||
|
@ -1160,8 +1331,6 @@ class ScreenProctoringAPIBinding {
|
|||
public static final String ATTR_SPS_ACTIVE = "spsExamActive";
|
||||
public static final String ATTR_SPS_ACCESS_DATA = "spsAccessData";
|
||||
|
||||
@JsonProperty("spsUserPWD")
|
||||
String spsUserPWD = null;
|
||||
@JsonProperty("spsSEBAccessUUID")
|
||||
String spsSEBAccessUUID = null;
|
||||
@JsonProperty("spsSEBAccessName")
|
||||
|
@ -1175,16 +1344,13 @@ class ScreenProctoringAPIBinding {
|
|||
}
|
||||
|
||||
@JsonCreator
|
||||
public SPSData(
|
||||
@JsonProperty("spsUserPWD") final String spsUserPWD,
|
||||
@JsonProperty("spsSEBAccessUUID") final String spsSEBAccessUUID,
|
||||
public SPSData(@JsonProperty("spsSEBAccessUUID") final String spsSEBAccessUUID,
|
||||
// NOTE: this is only for compatibility reasons, TODO as soon as possible
|
||||
@JsonProperty("spsSEBAccesUUID") final String spsSEBAccesUUID,
|
||||
@JsonProperty("spsSEBAccessName") final String spsSEBAccessName,
|
||||
@JsonProperty("spsSEBAccessPWD") final String spsSEBAccessPWD,
|
||||
@JsonProperty("psExamUUID") final String spsExamUUID) {
|
||||
|
||||
this.spsUserPWD = spsUserPWD;
|
||||
this.spsSEBAccessUUID = StringUtils.isNotBlank(spsSEBAccesUUID) ? spsSEBAccesUUID : spsSEBAccessUUID;
|
||||
this.spsSEBAccessName = spsSEBAccessName;
|
||||
this.spsSEBAccessPWD = spsSEBAccessPWD;
|
||||
|
|
|
@ -10,14 +10,13 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring;
|
|||
|
||||
import static ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_SCREEN_PROCTORING.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -184,7 +183,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
final boolean isEnabling = this.proctoringSettingsDAO.isScreenProctoringEnabled(exam.id);
|
||||
|
||||
if (isEnabling && !isSPSActive) {
|
||||
|
||||
// if screen proctoring has been enabled
|
||||
this.screenProctoringAPIBinding
|
||||
.startScreenProctoring(exam)
|
||||
.onError(error -> log.error(
|
||||
|
@ -197,9 +196,9 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
this.examDAO.markUpdate(exam.id);
|
||||
|
||||
} else if (!isEnabling && isSPSActive) {
|
||||
|
||||
// if screen proctoring has been disabled...
|
||||
this.screenProctoringAPIBinding
|
||||
.disposeScreenProctoring(exam)
|
||||
.deactivateScreenProctoring(exam)
|
||||
.onError(error -> log.error("Failed to dispose screen proctoring for exam: {}",
|
||||
exam,
|
||||
error))
|
||||
|
@ -301,7 +300,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.screenProctoringAPIBinding.activateSEBAccessOnSPS(exam, true);
|
||||
this.screenProctoringAPIBinding.activateScreenProctoring(exam);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -311,7 +310,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.screenProctoringAPIBinding.activateSEBAccessOnSPS(exam, false);
|
||||
this.screenProctoringAPIBinding.deactivateScreenProctoring(exam);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -330,6 +329,37 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLmsSetupChange(final LmsSetupChangeEvent event) {
|
||||
try {
|
||||
|
||||
if (event.activation == Activatable.ActivationAction.NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
examDAO.allActiveForLMSSetup(Arrays.asList(event.getLmsSetup().id))
|
||||
.getOrThrow()
|
||||
.forEach(exam -> {
|
||||
if (screenProctoringAPIBinding.isSPSActive(exam)) {
|
||||
if (event.activation == Activatable.ActivationAction.ACTIVATE) {
|
||||
this.screenProctoringAPIBinding.activateScreenProctoring(exam)
|
||||
.onError(error -> log.warn("Failed to re-activate SPS for exam: {} error: {}",
|
||||
exam.name,
|
||||
error.getMessage()));
|
||||
} else if (event.activation == Activatable.ActivationAction.DEACTIVATE) {
|
||||
this.screenProctoringAPIBinding.deactivateScreenProctoring(exam)
|
||||
.onError(error -> log.warn("Failed to deactivate SPS for exam: {} error: {}",
|
||||
exam.name,
|
||||
error.getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to apply LMSSetup change activation/deactivation to Screen Proctoring: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyScreenProctoringSession(final ClientConnectionRecord ccRecord) {
|
||||
|
||||
Long placeReservedInGroup = null;
|
||||
|
@ -457,7 +487,7 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
|||
private Result<Exam> deleteForExam(final Long examId) {
|
||||
return this.examDAO
|
||||
.byPK(examId)
|
||||
.map(this.screenProctoringAPIBinding::deleteScreenProctoring)
|
||||
.flatMap(this.screenProctoringAPIBinding::deactivateScreenProctoring)
|
||||
.map(this::cleanupAllLocalGroups)
|
||||
.onError(error -> log.error("Failed to delete SPS integration for exam: {}", examId, error));
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Cryptor;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamImportService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamUtils;
|
||||
|
|
|
@ -14,6 +14,7 @@ import ch.ethz.seb.sebserver.gbl.model.Activatable;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsTestService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -61,7 +62,8 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
private final LmsTestService lmsTestService;
|
||||
private final SEBRestrictionService sebRestrictionService;
|
||||
private final FullLmsIntegrationService fullLmsIntegrationService;
|
||||
final ApplicationEventPublisher applicationEventPublisher;
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
private final ScreenProctoringService screenProctoringService;
|
||||
|
||||
public LmsSetupController(
|
||||
final LmsSetupDAO lmsSetupDAO,
|
||||
|
@ -74,7 +76,8 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
final LmsTestService lmsTestService,
|
||||
final SEBRestrictionService sebRestrictionService,
|
||||
final FullLmsIntegrationService fullLmsIntegrationService,
|
||||
final ApplicationEventPublisher applicationEventPublisher) {
|
||||
final ApplicationEventPublisher applicationEventPublisher,
|
||||
final ScreenProctoringService screenProctoringService) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
|
@ -88,6 +91,7 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
this.sebRestrictionService = sebRestrictionService;
|
||||
this.fullLmsIntegrationService = fullLmsIntegrationService;
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
this.screenProctoringService = screenProctoringService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -166,20 +170,35 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
return super.notifySaved(entity, activation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<LmsSetup> validForActivation(final LmsSetup entity, final boolean activation) {
|
||||
return super.validForActivation(entity, activation)
|
||||
.map(lmsSetup -> {
|
||||
if (!activation) {
|
||||
// on deactivation remove all SEB restrictions and delete full integration if in place
|
||||
return sebRestrictionService
|
||||
.applyLMSSetupDeactivation(lmsSetup)
|
||||
.flatMap(fullLmsIntegrationService::applyLMSSetupDeactivation)
|
||||
.getOrThrow();
|
||||
}
|
||||
return entity;
|
||||
});
|
||||
}
|
||||
// @Override
|
||||
// protected Result<LmsSetup> validForActivation(final LmsSetup entity, final boolean activation) {
|
||||
// return super.validForActivation(entity, activation)
|
||||
// .map(lmsSetup -> {
|
||||
// if (!activation) {
|
||||
// // on deactivation remove all SEB restrictions and delete full integration if in place
|
||||
// return sebRestrictionService
|
||||
// .applyLMSSetupDeactivation(lmsSetup)
|
||||
// .onErrorDo(error -> {
|
||||
// log.warn("Failed to apply LMSSetup deactivation for SEB Restriction: ", error);
|
||||
// return lmsSetup;
|
||||
// })
|
||||
// .flatMap(fullLmsIntegrationService::applyLMSSetupDeactivation)
|
||||
// .onErrorDo(error -> {
|
||||
// log.warn("Failed to apply LMSSetup deactivation for LMS full integration: ", error);
|
||||
// return lmsSetup;
|
||||
// })
|
||||
// .flatMap(screenProctoringService::applyLMSSetupDeactivation)
|
||||
// .onErrorDo(error -> {
|
||||
// log.warn("Failed to apply LMSSetup deactivation for Screen Proctoring: ", error);
|
||||
// return lmsSetup;
|
||||
// })
|
||||
// .getOrThrow();
|
||||
// } else {
|
||||
//
|
||||
// }
|
||||
// return entity;
|
||||
// });
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected Result<LmsSetup> validForDelete(final LmsSetup entity) {
|
||||
|
@ -187,7 +206,7 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
// if there is a SEB Restriction involved, release all SEB Restriction for exams
|
||||
if (entity.lmsType.features.contains(LmsSetup.Features.SEB_RESTRICTION)) {
|
||||
sebRestrictionService
|
||||
.applyLMSSetupDeactivation(entity)
|
||||
.releaseAllRestrictionsOf(entity)
|
||||
.getOrThrow();
|
||||
}
|
||||
// if there is a full LMS integration involved, delete it first on LMS
|
||||
|
|
Loading…
Reference in a new issue