SEBSERV-417 fix check full integration available and fix Exam Config change apply
This commit is contained in:
parent
e0952da7f3
commit
b4907fcda9
11 changed files with 120 additions and 16 deletions
|
@ -18,6 +18,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationServi
|
|||
|
||||
public interface FullLmsIntegrationAPI {
|
||||
|
||||
boolean fullIntegrationActive();
|
||||
|
||||
/** Performs a test for the underling {@link LmsSetup } configuration and checks if the
|
||||
* LMS and the full LMS integration API of the LMS can be accessed or if there are some difficulties,
|
||||
* missing API functions
|
||||
|
@ -34,4 +36,6 @@ public interface FullLmsIntegrationAPI {
|
|||
Result<String> deleteConnectionDetails();
|
||||
|
||||
Result<QuizData> getQuizDataForRemoteImport(String examData);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl.ExamDeletionEvent;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamTemplateChangeEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsSetupChangeEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationChangeEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateEvent;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
@ -37,6 +38,8 @@ public interface FullLmsIntegrationService {
|
|||
void notifyConnectionConfigurationChange(ConnectionConfigurationChangeEvent event);
|
||||
@EventListener(ExamDeletionEvent.class)
|
||||
void notifyExamDeletion(ExamDeletionEvent event);
|
||||
@EventListener(ExamConfigUpdateEvent.class)
|
||||
void notifyExamConfigChange(ExamConfigUpdateEvent event);
|
||||
|
||||
/** Applies the exam data to LMS to inform the LMS that the exam exists on SEB Server site.
|
||||
* @param exam The Exam
|
||||
|
@ -75,6 +78,7 @@ public interface FullLmsIntegrationService {
|
|||
String quizId,
|
||||
AdHocAccountData adHocAccountData);
|
||||
|
||||
|
||||
final class AdHocAccountData {
|
||||
public final String userId;
|
||||
public final String username;
|
||||
|
|
|
@ -51,6 +51,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionService;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationChangeEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -149,12 +150,10 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
@Override
|
||||
public Result<Exam> applyExamDataToLMS(final Exam exam) {
|
||||
return Result.tryCatch(() -> {
|
||||
final LmsSetup lmsSetup = lmsSetupDAO.byPK(exam.lmsSetupId).getOrThrow();
|
||||
if (lmsSetup.lmsType.features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||
if (hasFullIntegration(exam.lmsSetupId)) {
|
||||
this.applyExamData(exam, !exam.active);
|
||||
this.applyConnectionConfiguration(exam);
|
||||
}
|
||||
|
||||
return exam;
|
||||
});
|
||||
|
||||
|
@ -168,10 +167,29 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyExamConfigChange(final ExamConfigUpdateEvent event) {
|
||||
try {
|
||||
|
||||
final Exam exam = examDAO.byPK(event.examId).getOrThrow();
|
||||
if (!hasFullIntegration(exam.lmsSetupId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.applyExamData(exam, !exam.active);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error(
|
||||
"Failed to apply Exam Configuration change to fully integrated LMS for exam: {}",
|
||||
event.examId,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLmsSetupChange(final LmsSetupChangeEvent event) {
|
||||
final LmsSetup lmsSetup = event.getLmsSetup();
|
||||
if (!lmsSetup.getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||
if (!hasFullIntegration(lmsSetup.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -206,6 +224,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
|
||||
lmsSetupDAO.idsOfActiveWithFullIntegration(examTemplate.institutionId)
|
||||
.onSuccess(all -> all.stream()
|
||||
.filter(this::hasFullIntegration)
|
||||
.map(this::applyFullLmsIntegration)
|
||||
.forEach(res ->
|
||||
res.onError(error -> log.warn(
|
||||
|
@ -229,15 +248,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.forEach(this::applyConnectionConfiguration);
|
||||
}
|
||||
|
||||
private boolean needsConnectionConfigurationChange(final Exam exam, final Long ccId) {
|
||||
if (exam.status == Exam.ExamStatus.ARCHIVED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String configId = getConnectionConfigurationId(exam);
|
||||
return StringUtils.isNotBlank(configId) && configId.equals(String.valueOf(ccId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<IntegrationData> applyFullLmsIntegration(final Long lmsSetupId) {
|
||||
return lmsSetupDAO
|
||||
|
@ -544,6 +554,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
}
|
||||
|
||||
private Exam applyExamData(final Exam exam, final boolean deletion) {
|
||||
if (!hasFullIntegration(exam.lmsSetupId)) {
|
||||
return exam;
|
||||
}
|
||||
if (exam.examTemplateId == null) {
|
||||
throw new IllegalStateException("Exam has no template id: " + exam.getName());
|
||||
}
|
||||
|
@ -611,6 +624,27 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
|||
.getOr(exam);
|
||||
}
|
||||
|
||||
private boolean hasFullIntegration(final Long lmsSetupId) {
|
||||
final LmsAPITemplate lmsAPITemplate = this.lmsAPITemplateCacheService
|
||||
.getLmsAPITemplate(lmsSetupId)
|
||||
.getOrThrow();
|
||||
final LmsSetup lmsSetup = lmsAPITemplate.lmsSetup();
|
||||
if (!lmsSetup.getLmsType().features.contains(LmsSetup.Features.LMS_FULL_INTEGRATION)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lmsAPITemplate.fullIntegrationActive();
|
||||
}
|
||||
|
||||
private boolean needsConnectionConfigurationChange(final Exam exam, final Long ccId) {
|
||||
if (exam.status == Exam.ExamStatus.ARCHIVED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String configId = getConnectionConfigurationId(exam);
|
||||
return StringUtils.isNotBlank(configId) && configId.equals(String.valueOf(ccId));
|
||||
}
|
||||
|
||||
private String getAPIRootURL() {
|
||||
return webserviceInfo.getExternalServerURL() + lmsAPIEndpoint;
|
||||
}
|
||||
|
|
|
@ -500,6 +500,10 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
|||
return protectedRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fullIntegrationActive() {
|
||||
return this.lmsIntegrationAPI.fullIntegrationActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LmsSetupTestResult testFullIntegrationAPI() {
|
||||
|
|
|
@ -422,6 +422,13 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms
|
|||
.map(x -> exam);
|
||||
}
|
||||
|
||||
/// Full Integration API - Not integrated yet
|
||||
|
||||
@Override
|
||||
public boolean fullIntegrationActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LmsSetupTestResult testFullIntegrationAPI() {
|
||||
return LmsSetupTestResult.ofAPINotSupported(LmsType.ANS_DELFT);
|
||||
|
|
|
@ -19,6 +19,11 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationServi
|
|||
|
||||
public class MockupFullIntegration implements FullLmsIntegrationAPI {
|
||||
|
||||
@Override
|
||||
public boolean fullIntegrationActive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LmsSetupTestResult testFullIntegrationAPI() {
|
||||
return LmsSetupTestResult.ofAPINotSupported(LmsSetup.LmsType.MOODLE_PLUGIN);
|
||||
|
|
|
@ -64,6 +64,11 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
|||
Constants.TRUE_STRING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fullIntegrationActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LmsSetupTestResult testFullIntegrationAPI() {
|
||||
final LmsSetupTestResult attributesCheck = this.restTemplateFactory.test();
|
||||
|
@ -80,7 +85,12 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
|||
}
|
||||
|
||||
try {
|
||||
|
||||
final MoodleAPIRestTemplate restTemplate = restTemplateRequest.get();
|
||||
if (restTemplate.getMoodlePluginVersion() != MoodleAPIRestTemplate.MoodlePluginVersion.V2_0) {
|
||||
throw new RuntimeException("Old Moodle Plugin Version: " + restTemplate.getMoodlePluginVersion().name());
|
||||
}
|
||||
|
||||
restTemplate.testAPIConnection(
|
||||
FUNCTION_NAME_SEBSERVER_CONNECTION,
|
||||
FUNCTION_NAME_SEBSERVER_CONNECTION_DELETE,
|
||||
|
|
|
@ -409,6 +409,13 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm
|
|||
.map(x -> exam);
|
||||
}
|
||||
|
||||
/// Full Integration API - Not integrated yet
|
||||
|
||||
@Override
|
||||
public boolean fullIntegrationActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LmsSetupTestResult testFullIntegrationAPI() {
|
||||
return LmsSetupTestResult.ofAPINotSupported(LmsType.OPEN_OLAT);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, IT Services
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class ExamConfigUpdateEvent extends ApplicationEvent {
|
||||
|
||||
public final Long examId;
|
||||
public ExamConfigUpdateEvent(final Long examId) {
|
||||
super(examId);
|
||||
this.examId = examId;
|
||||
}
|
||||
}
|
|
@ -14,9 +14,12 @@ import java.util.function.Function;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.FullLmsIntegrationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateEvent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
@ -49,6 +52,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
private final ExamUpdateHandler examUpdateHandler;
|
||||
private final ExamAdminService examAdminService;
|
||||
private final ExamConfigurationValueService examConfigurationValueService;
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
|
||||
protected ExamConfigUpdateServiceImpl(
|
||||
|
@ -58,7 +62,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
final ExamSessionService examSessionService,
|
||||
final ExamUpdateHandler examUpdateHandler,
|
||||
final ExamAdminService examAdminService,
|
||||
final ExamConfigurationValueService examConfigurationValueService) {
|
||||
final ExamConfigurationValueService examConfigurationValueService,
|
||||
final ApplicationEventPublisher applicationEventPublisher) {
|
||||
|
||||
this.examDAO = examDAO;
|
||||
this.configurationDAO = configurationDAO;
|
||||
|
@ -67,6 +72,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
this.examUpdateHandler = examUpdateHandler;
|
||||
this.examAdminService = examAdminService;
|
||||
this.examConfigurationValueService = examConfigurationValueService;
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
// processing:
|
||||
|
@ -102,7 +108,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
final Collection<Exam> exams = lockForUpdate(examIdsFirstCheck, updateId)
|
||||
.stream()
|
||||
.map(Result::getOrThrow)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
final Collection<Long> examsIds = exams
|
||||
.stream()
|
||||
|
@ -243,6 +249,9 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
.releaseLock(exam.id, updateId)
|
||||
.onError(t -> log.error("Failed to release lock for exam: {}", exam));
|
||||
|
||||
// notify...
|
||||
applicationEventPublisher.publishEvent(new ExamConfigUpdateEvent(exam.id));
|
||||
|
||||
return result;
|
||||
})
|
||||
.onError(t -> this.examDAO.forceUnlock(mapping.examId));
|
||||
|
|
|
@ -193,7 +193,7 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
|
|||
final PermissionDeniedException ex,
|
||||
final WebRequest request) {
|
||||
|
||||
log.info("Permission Denied Exception: ", ex);
|
||||
log.info("Permission Denied Exception: {}", ex.getMessage());
|
||||
return APIMessage.ErrorMessage.FORBIDDEN
|
||||
.createErrorResponse(ex.getMessage());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue