SEBSERV-418 removed SEB config upload to Moodle and call set_exam_data on change instead
This commit is contained in:
parent
d291e21543
commit
01bd5c5558
8 changed files with 75 additions and 144 deletions
|
@ -31,7 +31,7 @@ public interface FullLmsIntegrationAPI {
|
||||||
|
|
||||||
Result<ExamData> applyExamData(ExamData examData);
|
Result<ExamData> applyExamData(ExamData examData);
|
||||||
|
|
||||||
Result<Exam> applyConnectionConfiguration(Exam exam, byte[] configData);
|
//Result<Exam> applyConnectionConfiguration(Exam exam, byte[] configData);
|
||||||
|
|
||||||
Result<String> deleteConnectionDetails();
|
Result<String> deleteConnectionDetails();
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PipedInputStream;
|
|
||||||
import java.io.PipedOutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -53,7 +50,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigu
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConnectionConfigurationService;
|
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.ExamConfigUpdateEvent;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -152,11 +148,9 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
if (hasFullIntegration(exam.lmsSetupId)) {
|
if (hasFullIntegration(exam.lmsSetupId)) {
|
||||||
this.applyExamData(exam, !exam.active);
|
this.applyExamData(exam, !exam.active);
|
||||||
this.applyConnectionConfiguration(exam);
|
|
||||||
}
|
}
|
||||||
return exam;
|
return exam;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -245,7 +239,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.getOr(Collections.emptyList())
|
.getOr(Collections.emptyList())
|
||||||
.stream()
|
.stream()
|
||||||
.filter(exam -> this.needsConnectionConfigurationChange(exam, event.configId))
|
.filter(exam -> this.needsConnectionConfigurationChange(exam, event.configId))
|
||||||
.forEach(this::applyConnectionConfiguration);
|
.forEach(exam -> applyExamData(exam, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -332,8 +326,7 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.map(template -> getQuizData(template, courseId, quizId, examData))
|
.map(template -> getQuizData(template, courseId, quizId, examData))
|
||||||
.map(createExam(examTemplateId, showQuitLink, quitPassword))
|
.map(createExam(examTemplateId, showQuitLink, quitPassword))
|
||||||
.map(exam -> applyExamData(exam, false))
|
.map(exam -> applyExamData(exam, false))
|
||||||
.map(this::applySEBClientRestrictionIfRunning)
|
.map(this::applySEBClientRestrictionIfRunning);
|
||||||
.map(this::applyConnectionConfiguration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exam applySEBClientRestrictionIfRunning(final Exam exam) {
|
private Exam applySEBClientRestrictionIfRunning(final Exam exam) {
|
||||||
|
@ -502,7 +495,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
.byModelId(examTemplateId)
|
.byModelId(examTemplateId)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
|
|
||||||
// import exam
|
// import exam
|
||||||
final POSTMapper post = new POSTMapper(null, null);
|
final POSTMapper post = new POSTMapper(null, null);
|
||||||
post.putIfAbsent(Domain.EXAM.ATTR_EXAM_TEMPLATE_ID, examTemplateId);
|
post.putIfAbsent(Domain.EXAM.ATTR_EXAM_TEMPLATE_ID, examTemplateId);
|
||||||
|
@ -526,12 +518,11 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exam checkDeletion(final Exam exam) {
|
private Exam checkDeletion(final Exam exam) {
|
||||||
// TODO check if Exam can be deleted according to the Spec
|
|
||||||
|
|
||||||
if (exam.status != Exam.ExamStatus.RUNNING) {
|
if (exam.status != Exam.ExamStatus.RUNNING) {
|
||||||
return exam;
|
return exam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if exam is running and has active SEB client connections, it cannot be deleted
|
||||||
final Integer active = this.clientConnectionDAO
|
final Integer active = this.clientConnectionDAO
|
||||||
.getAllActiveConnectionTokens(exam.id)
|
.getAllActiveConnectionTokens(exam.id)
|
||||||
.map(Collection::size)
|
.map(Collection::size)
|
||||||
|
@ -545,15 +536,6 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
throw new APIMessage.APIMessageException(
|
throw new APIMessage.APIMessageException(
|
||||||
APIMessage.ErrorMessage.INTEGRITY_VALIDATION
|
APIMessage.ErrorMessage.INTEGRITY_VALIDATION
|
||||||
.of("Exam currently has active SEB Client connections."));
|
.of("Exam currently has active SEB Client connections."));
|
||||||
|
|
||||||
// check if there are no active SEB client connections
|
|
||||||
// if (this.examSessionService.hasActiveSEBClientConnections(exam.id)) {
|
|
||||||
// throw new APIMessage.APIMessageException(
|
|
||||||
// APIMessage.ErrorMessage.INTEGRITY_VALIDATION
|
|
||||||
// .of("Exam currently has active SEB Client connections."));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return exam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -637,38 +619,37 @@ public class FullLmsIntegrationServiceImpl implements FullLmsIntegrationService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exam applyConnectionConfiguration(final Exam exam) {
|
// private Exam applyConnectionConfiguration(final Exam exam) {
|
||||||
return lmsAPITemplateCacheService
|
// return lmsAPITemplateCacheService
|
||||||
.getLmsAPITemplate(exam.lmsSetupId)
|
// .getLmsAPITemplate(exam.lmsSetupId)
|
||||||
.flatMap(template -> {
|
// .flatMap(template -> {
|
||||||
final String connectionConfigId = getConnectionConfigurationId(exam);
|
// final String connectionConfigId = getConnectionConfigurationId(exam);
|
||||||
|
//
|
||||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
// final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
final PipedOutputStream pout;
|
// final PipedOutputStream pout;
|
||||||
final PipedInputStream pin;
|
// final PipedInputStream pin;
|
||||||
try {
|
// try {
|
||||||
pout = new PipedOutputStream();
|
// pout = new PipedOutputStream();
|
||||||
pin = new PipedInputStream(pout);
|
// pin = new PipedInputStream(pout);
|
||||||
|
//
|
||||||
this.connectionConfigurationService
|
// this.connectionConfigurationService
|
||||||
.exportSEBClientConfiguration(pout, connectionConfigId, exam.id);
|
// .exportSEBClientConfiguration(pout, connectionConfigId, exam.id);
|
||||||
|
//
|
||||||
out.flush();
|
// out.flush();
|
||||||
|
//
|
||||||
IOUtils.copyLarge(pin, out);
|
// IOUtils.copyLarge(pin, out);
|
||||||
|
//
|
||||||
// TODO check if this works as expected
|
// return template.applyConnectionConfiguration(exam, out.toByteArray());
|
||||||
return template.applyConnectionConfiguration(exam, out.toByteArray());
|
//
|
||||||
|
// } catch (final Exception e) {
|
||||||
} catch (final Exception e) {
|
// throw new RuntimeException("Failed to stream output", e);
|
||||||
throw new RuntimeException("Failed to stream output", e);
|
// } finally {
|
||||||
} finally {
|
// IOUtils.closeQuietly(out);
|
||||||
IOUtils.closeQuietly(out);
|
// }
|
||||||
}
|
// })
|
||||||
})
|
// .onError(error -> log.error("Failed to apply ConnectionConfiguration for exam: {} error: ", exam, error))
|
||||||
.onError(error -> log.error("Failed to apply ConnectionConfiguration for exam: {} error: ", exam, error))
|
// .getOr(exam);
|
||||||
.getOr(exam);
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasFullIntegration(final Long lmsSetupId) {
|
private boolean hasFullIntegration(final Long lmsSetupId) {
|
||||||
// no LMS
|
// no LMS
|
||||||
|
|
|
@ -546,23 +546,6 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
|
||||||
.getOrThrow());
|
.getOrThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
|
||||||
if (this.lmsIntegrationAPI == null) {
|
|
||||||
return Result.ofError(
|
|
||||||
new UnsupportedOperationException("LMS Integration API Not Supported For: " + getType().name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Apply Connection Configuration for exam: {} for LMSSetup: {}", exam, lmsSetup());
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.examRequest.protectedRun(() -> this.lmsIntegrationAPI
|
|
||||||
.applyConnectionConfiguration(exam, configData)
|
|
||||||
.getOrThrow());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<String> deleteConnectionDetails() {
|
public Result<String> deleteConnectionDetails() {
|
||||||
if (this.lmsIntegrationAPI == null) {
|
if (this.lmsIntegrationAPI == null) {
|
||||||
|
|
|
@ -444,11 +444,6 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms
|
||||||
return Result.ofRuntimeError("Not Supported");
|
return Result.ofRuntimeError("Not Supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
|
||||||
return Result.ofRuntimeError("Not Supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<String> deleteConnectionDetails() {
|
public Result<String> deleteConnectionDetails() {
|
||||||
return Result.ofRuntimeError("Not Supported");
|
return Result.ofRuntimeError("Not Supported");
|
||||||
|
|
|
@ -39,11 +39,6 @@ public class MockupFullIntegration implements FullLmsIntegrationAPI {
|
||||||
return Result.ofRuntimeError("Not Supported");
|
return Result.ofRuntimeError("Not Supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
|
||||||
return Result.ofRuntimeError("Not Supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<String> deleteConnectionDetails() {
|
public Result<String> deleteConnectionDetails() {
|
||||||
return Result.ofRuntimeError("TODO");
|
return Result.ofRuntimeError("TODO");
|
||||||
|
|
|
@ -452,32 +452,12 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
|
||||||
new HttpEntity<>(body, headers);
|
new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
final ResponseEntity<String> exchange = super.exchange(
|
final ResponseEntity<String> exchange = super.exchange(
|
||||||
uri.toString(),
|
uri.append("?token=").append(this.accessToken).toString(),
|
||||||
HttpMethod.POST,
|
HttpMethod.POST,
|
||||||
requestEntity,
|
requestEntity,
|
||||||
String.class);
|
String.class);
|
||||||
|
|
||||||
return exchange.getBody();
|
return exchange.getBody();
|
||||||
|
|
||||||
// multiPartAttributes.add("token", this.accessToken.toString());
|
|
||||||
//
|
|
||||||
// queryAttributes.forEach((key, values) -> {
|
|
||||||
// if (values.isEmpty()) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (uri.toString().contains("?")) {
|
|
||||||
// uri.append("&").append(key).append("=").append(values.get(0));
|
|
||||||
// } else {
|
|
||||||
// uri.append("?").append(key).append("=").append(values.get(0));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// log.info("Upload to Moodle url: {}", uri.toString());
|
|
||||||
//
|
|
||||||
// return super.postForObject(
|
|
||||||
// uri.toString(),
|
|
||||||
// multiPartAttributes,
|
|
||||||
// String.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String doRequest(
|
private String doRequest(
|
||||||
|
|
|
@ -239,43 +239,43 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
// public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
||||||
return Result.tryCatch(() -> {
|
// return Result.tryCatch(() -> {
|
||||||
|
|
||||||
final String quizId = MoodleUtils.getQuizId(exam.externalId);
|
|
||||||
final String fileName = getConnectionConfigFileName(exam);
|
|
||||||
|
|
||||||
// final MultiValueMap<String, Object> multiPartAttributes = new LinkedMultiValueMap<>();
|
|
||||||
// multiPartAttributes.add("quizid", quizId);
|
|
||||||
// multiPartAttributes.add("name", fileName);
|
|
||||||
// multiPartAttributes.add("filename", fileName);
|
|
||||||
|
|
||||||
// final MultiValueMap<String, String> queryAttributes = new LinkedMultiValueMap<>();
|
|
||||||
// //queryAttributes.add("quizid", quizId);
|
|
||||||
// final ByteArrayResource contentsAsResource = new ByteArrayResource(configData) {
|
|
||||||
// @Override
|
|
||||||
// public String getFilename() {
|
|
||||||
// return fileName; // Filename has to be returned in order to be able to post.
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
//
|
||||||
// multiPartAttributes.add("file", contentsAsResource);
|
// final String quizId = MoodleUtils.getQuizId(exam.externalId);
|
||||||
|
// final String fileName = getConnectionConfigFileName(exam);
|
||||||
final MoodleAPIRestTemplate rest = getRestTemplate().getOrThrow();
|
//
|
||||||
final String response = rest.uploadMultiPart(
|
//// final MultiValueMap<String, Object> multiPartAttributes = new LinkedMultiValueMap<>();
|
||||||
UPLOAD_ENDPOINT,
|
//// multiPartAttributes.add("quizid", quizId);
|
||||||
quizId,
|
//// multiPartAttributes.add("name", fileName);
|
||||||
fileName,
|
//// multiPartAttributes.add("filename", fileName);
|
||||||
configData);
|
//
|
||||||
|
//// final MultiValueMap<String, String> queryAttributes = new LinkedMultiValueMap<>();
|
||||||
if (response != null) {
|
//// //queryAttributes.add("quizid", quizId);
|
||||||
log.info("Upload Connection Configuration to Moodle: quizid: {}, fileName: {} response: {}", quizId, fileName, response );
|
//// final ByteArrayResource contentsAsResource = new ByteArrayResource(configData) {
|
||||||
}
|
//// @Override
|
||||||
|
//// public String getFilename() {
|
||||||
return exam;
|
//// return fileName; // Filename has to be returned in order to be able to post.
|
||||||
});
|
//// }
|
||||||
}
|
//// };
|
||||||
|
////
|
||||||
|
//// multiPartAttributes.add("file", contentsAsResource);
|
||||||
|
//
|
||||||
|
// final MoodleAPIRestTemplate rest = getRestTemplate().getOrThrow();
|
||||||
|
// final String response = rest.uploadMultiPart(
|
||||||
|
// UPLOAD_ENDPOINT,
|
||||||
|
// quizId,
|
||||||
|
// fileName,
|
||||||
|
// configData);
|
||||||
|
//
|
||||||
|
// if (response != null) {
|
||||||
|
// log.info("Upload Connection Configuration to Moodle: quizid: {}, fileName: {} response: {}", quizId, fileName, response );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return exam;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
private String getConnectionConfigFileName(final Exam exam) {
|
private String getConnectionConfigFileName(final Exam exam) {
|
||||||
return "SEBServerConnectionConfiguration-" + exam.id + ".seb";
|
return "SEBServerConnectionConfiguration-" + exam.id + ".seb";
|
||||||
|
@ -317,7 +317,9 @@ public class MoodlePluginFullIntegration implements FullLmsIntegrationAPI {
|
||||||
public Result<QuizData> getQuizDataForRemoteImport(final String examData) {
|
public Result<QuizData> getQuizDataForRemoteImport(final String examData) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
log.info("****** Try to parse import exam data sent by Moodle on Exam import: {}", examData);
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Try to parse import exam data sent by Moodle on Exam import: {}", examData);
|
||||||
|
}
|
||||||
|
|
||||||
final LmsSetup lmsSetup = this.restTemplateFactory.getApiTemplateDataSupplier().getLmsSetup();
|
final LmsSetup lmsSetup = this.restTemplateFactory.getApiTemplateDataSupplier().getLmsSetup();
|
||||||
final String urlPrefix = (lmsSetup.lmsApiUrl.endsWith(Constants.URL_PATH_SEPARATOR))
|
final String urlPrefix = (lmsSetup.lmsApiUrl.endsWith(Constants.URL_PATH_SEPARATOR))
|
||||||
|
|
|
@ -431,11 +431,6 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm
|
||||||
return Result.ofRuntimeError("Not Supported");
|
return Result.ofRuntimeError("Not Supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result<Exam> applyConnectionConfiguration(final Exam exam, final byte[] configData) {
|
|
||||||
return Result.ofRuntimeError("Not Supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<String> deleteConnectionDetails() {
|
public Result<String> deleteConnectionDetails() {
|
||||||
return Result.ofRuntimeError("Not Supported");
|
return Result.ofRuntimeError("Not Supported");
|
||||||
|
|
Loading…
Reference in a new issue