diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/CourseAccessAPI.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/CourseAccessAPI.java
index 7f4ccaf9..879a2ba1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/CourseAccessAPI.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/CourseAccessAPI.java
@@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms;
import java.util.Collection;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
@@ -52,20 +51,6 @@ public interface CourseAccessAPI {
}
}
- /** Get an unsorted List of filtered {@link QuizData } from the LMS course/quiz API
- *
- * @param filterMap the {@link FilterMap } to get a filtered result. Possible filter attributes are:
- *
- *
- * {@link QuizData.FILTER_ATTR_QUIZ_NAME } The quiz name filter text (exclude all names that do not contain the given text)
- * {@link QuizData.FILTER_ATTR_START_TIME } The quiz start time (exclude all quizzes that starts before)
- *
- *
- * @return Result of an unsorted List of filtered {@link QuizData } from the LMS course/quiz API
- * or refer to an error when happened */
- @Deprecated
- Result> getQuizzes(FilterMap filterMap);
-
void fetchQuizzes(FilterMap filterMap, AsyncQuizFetchBuffer asyncQuizFetchBuffer);
/** Get all {@link QuizData } for the set of {@link QuizData } identifiers from LMS API in a collection
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java
index 60561dcf..1b28a369 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPITemplateAdapter.java
@@ -9,7 +9,6 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
@@ -221,26 +220,6 @@ public class LmsAPITemplateAdapter implements LmsAPITemplate {
return LmsSetupTestResult.ofAPINotSupported(getType());
}
- @Override
- @Deprecated
- public Result> getQuizzes(final FilterMap filterMap) {
-
- if (this.courseAccessAPI == null) {
- return Result
- .ofError(new UnsupportedOperationException("Course API Not Supported For: " + getType().name()));
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Get quizzes for LMSSetup: {}", lmsSetup());
- }
-
- return this.courseAccessAPI
- .getQuizzes(filterMap)
- .onError(error -> log.error(
- "Failed to run protectedQuizzesRequest: {}",
- error.getMessage()));
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
if (this.courseAccessAPI == null) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java
index 25b85a07..f21988bb 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java
@@ -165,15 +165,6 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms
return LmsSetupTestResult.ofOkay(LmsType.ANS_DELFT);
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return this
- .allQuizzesRequest(filterMap)
- .map(quizzes -> quizzes.stream()
- .filter(LmsAPIService.quizFilterPredicate(filterMap))
- .collect(Collectors.toList()));
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
this.allQuizzesRequest(filterMap)
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseAccess.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseAccess.java
index f530d2a7..8be2e55c 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseAccess.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/edx/OpenEdxCourseAccess.java
@@ -140,11 +140,6 @@ final class OpenEdxCourseAccess extends AbstractCachedCourseAccess implements Co
return LmsSetupTestResult.ofOkay(LmsType.OPEN_EDX);
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return getRestTemplate().map(this::collectAllQuizzes);
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
try {
@@ -360,25 +355,6 @@ final class OpenEdxCourseAccess extends AbstractCachedCourseAccess implements Co
});
}
- private ArrayList collectAllQuizzes(final OAuth2RestTemplate restTemplate) {
- final LmsSetup lmsSetup = getApiTemplateDataSupplier().getLmsSetup();
- final String externalStartURI = getExternalLMSServerAddress(lmsSetup);
- return collectAllCourses(
- lmsSetup.lmsApiUrl + OPEN_EDX_DEFAULT_COURSE_ENDPOINT,
- restTemplate)
- .stream()
- .reduce(
- new ArrayList<>(),
- (list, courseData) -> {
- list.add(quizDataOf(lmsSetup, courseData, externalStartURI));
- return list;
- },
- (list1, list2) -> {
- list1.addAll(list2);
- return list1;
- });
- }
-
private String getExternalLMSServerAddress(final LmsSetup lmsSetup) {
final String externalAddressAlias = this.webserviceInfo.getLmsExternalAddressAlias(lmsSetup.lmsApiUrl);
String _externalStartURI = lmsSetup.lmsApiUrl + OPEN_EDX_DEFAULT_COURSE_START_URL_PREFIX;
@@ -466,22 +442,6 @@ final class OpenEdxCourseAccess extends AbstractCachedCourseAccess implements Co
}
}
- private List collectAllCourses(final String pageURI, final OAuth2RestTemplate restTemplate) {
- final List collector = new ArrayList<>();
- EdXPage page = getEdxPage(pageURI, restTemplate).getBody();
- if (page != null) {
- collector.addAll(page.results);
- while (page != null && StringUtils.isNotBlank(page.next)) {
- page = getEdxPage(page.next, restTemplate).getBody();
- if (page != null) {
- collector.addAll(page.results);
- }
- }
- }
-
- return collector;
- }
-
private ResponseEntity getEdxPage(final String pageURI, final OAuth2RestTemplate restTemplate) {
final HttpHeaders httpHeaders = new HttpHeaders();
return restTemplate.exchange(
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockCourseAccessAPI.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockCourseAccessAPI.java
index c8bf545a..3163ee38 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockCourseAccessAPI.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockCourseAccessAPI.java
@@ -160,27 +160,6 @@ public class MockCourseAccessAPI implements CourseAccessAPI {
return missingAttrs;
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return Result.tryCatch(() -> {
- if (!authenticate()) {
- throw new IllegalArgumentException("Wrong clientId or secret");
- }
-
- if (this.simulateLatency) {
- final int seconds = this.random.nextInt(20);
- System.out.println("************ Mockup LMS wait for " + seconds + " seconds before respond");
- Thread.sleep(seconds * 1000);
- }
-
- return this.mockups
- .stream()
- .map(this::getExternalAddressAlias)
- .filter(LmsAPIService.quizFilterPredicate(filterMap))
- .collect(Collectors.toList());
- });
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
if (!authenticate()) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccess.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccess.java
index 5789e4fa..fcaa394e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccess.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccess.java
@@ -22,7 +22,6 @@ import java.util.stream.Stream;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
-import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
@@ -59,8 +58,6 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.CourseQuizData;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.Courses;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.MoodleUserDetails;
-import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader.CourseDataShort;
-import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader.CourseQuizShort;
/** Implements the LmsAPITemplate for Open edX LMS Course API access.
*
@@ -78,7 +75,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.Mood
* possibly make this synchronous fetch strategy obsolete in the future. */
public class MoodleCourseAccess implements CourseAccessAPI {
- private static final long INITIAL_WAIT_TIME = 3 * Constants.SECOND_IN_MILLIS;
+ //private static final long INITIAL_WAIT_TIME = 3 * Constants.SECOND_IN_MILLIS;
private static final Logger log = LoggerFactory.getLogger(MoodleCourseAccess.class);
@@ -101,7 +98,6 @@ public class MoodleCourseAccess implements CourseAccessAPI {
private final JSONMapper jsonMapper;
private final MoodleRestTemplateFactory restTemplateFactory;
- private final MoodleCourseDataAsyncLoader moodleCourseDataAsyncLoader;
private final boolean prependShortCourseName;
private final CircuitBreaker protectedMoodlePageCall;
private final int pageSize;
@@ -113,11 +109,9 @@ public class MoodleCourseAccess implements CourseAccessAPI {
final JSONMapper jsonMapper,
final AsyncService asyncService,
final MoodleRestTemplateFactory restTemplateFactory,
- final MoodleCourseDataAsyncLoader moodleCourseDataAsyncLoader,
final Environment environment) {
this.jsonMapper = jsonMapper;
- this.moodleCourseDataAsyncLoader = moodleCourseDataAsyncLoader;
this.restTemplateFactory = restTemplateFactory;
this.prependShortCourseName = BooleanUtils.toBoolean(environment.getProperty(
@@ -176,16 +170,6 @@ public class MoodleCourseAccess implements CourseAccessAPI {
return LmsSetupTestResult.ofOkay(LmsType.MOODLE);
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return Result.tryCatch(() -> getRestTemplate()
- .map(template -> collectAllQuizzes(template, filterMap))
- .map(quizzes -> quizzes.stream()
- .filter(LmsAPIService.quizFilterPredicate(filterMap))
- .collect(Collectors.toList()))
- .getOr(Collections.emptyList()));
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
try {
@@ -297,35 +281,6 @@ public class MoodleCourseAccess implements CourseAccessAPI {
@Override
public Result getQuiz(final String id) {
return Result.tryCatch(() -> {
-
- final Map cachedCourseData = this.moodleCourseDataAsyncLoader
- .getCachedCourseData();
-
- final String courseId = MoodleUtils.getCourseId(id);
- final String quizId = MoodleUtils.getQuizId(id);
- if (cachedCourseData.containsKey(courseId)) {
- final CourseDataShort courseData = cachedCourseData.get(courseId);
- final CourseQuizShort quiz = courseData.quizzes
- .stream()
- .filter(q -> q.id.equals(quizId))
- .findFirst()
- .orElse(null);
-
- if (quiz != null) {
- final Map additionalAttrs = new HashMap<>();
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_CREATION_TIME,
- String.valueOf(courseData.time_created));
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_SHORT_NAME, courseData.short_name);
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_ID_NUMBER, courseData.idnumber);
- final LmsSetup lmsSetup = getApiTemplateDataSupplier().getLmsSetup();
- final String urlPrefix = (lmsSetup.lmsApiUrl.endsWith(Constants.URL_PATH_SEPARATOR))
- ? lmsSetup.lmsApiUrl + MOODLE_QUIZ_START_URL_PATH
- : lmsSetup.lmsApiUrl + Constants.URL_PATH_SEPARATOR + MOODLE_QUIZ_START_URL_PATH;
-
- return createQuizData(lmsSetup, courseData, urlPrefix, additionalAttrs, quiz);
- }
- }
-
// get from LMS in protected request
final Set ids = Stream.of(id).collect(Collectors.toSet());
return getRestTemplate()
@@ -475,72 +430,6 @@ public class MoodleCourseAccess implements CourseAccessAPI {
return Result.ofError(new UnsupportedOperationException("not available yet"));
}
- public void clearCache() {
- this.moodleCourseDataAsyncLoader.clearCache();
- }
-
- private List collectAllQuizzes(
- final MoodleAPIRestTemplate restTemplate,
- final FilterMap filterMap) {
-
- final LmsSetup lmsSetup = getApiTemplateDataSupplier().getLmsSetup();
- final String urlPrefix = (lmsSetup.lmsApiUrl.endsWith(Constants.URL_PATH_SEPARATOR))
- ? lmsSetup.lmsApiUrl + MOODLE_QUIZ_START_URL_PATH
- : lmsSetup.lmsApiUrl + Constants.URL_PATH_SEPARATOR + MOODLE_QUIZ_START_URL_PATH;
-
- final DateTime quizFromTime = (filterMap != null) ? filterMap.getQuizFromTime() : null;
- final long fromCutTime = (quizFromTime != null) ? Utils.toUnixTimeInSeconds(quizFromTime) : -1;
-
- // Verify and call the proper strategy to get the course and quiz data
- Collection courseQuizData = Collections.emptyList();
- if (this.moodleCourseDataAsyncLoader.isRunning()) {
- courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData().values();
- } else if (this.moodleCourseDataAsyncLoader.getLastRunTime() <= 0) {
- // set cut time if available
- if (fromCutTime >= 0) {
- this.moodleCourseDataAsyncLoader.setFromCutTime(fromCutTime);
- }
- // first run async and wait some time, get what is there
- this.moodleCourseDataAsyncLoader.loadAsync(restTemplate);
- try {
- Thread.sleep(INITIAL_WAIT_TIME);
- courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData().values();
- } catch (final Exception e) {
- log.error("Failed to wait for first load run: ", e);
- return Collections.emptyList();
- }
- } else if (this.moodleCourseDataAsyncLoader.isLongRunningTask()) {
- // on long running tasks if we have a different fromCutTime as before
- // kick off the lazy loading task immediately with the new time filter
- courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData().values();
- if (fromCutTime > 0 && fromCutTime != this.moodleCourseDataAsyncLoader.getFromCutTime()) {
- this.moodleCourseDataAsyncLoader.setFromCutTime(fromCutTime);
- this.moodleCourseDataAsyncLoader.loadAsync(restTemplate);
- // otherwise kick off only if the last fetch task was then minutes ago
- } else if (Utils.getMillisecondsNow() - this.moodleCourseDataAsyncLoader.getLastRunTime() > 10
- * Constants.MINUTE_IN_MILLIS) {
- this.moodleCourseDataAsyncLoader.loadAsync(restTemplate);
- }
-
- } else {
- // just run the task in sync
- if (fromCutTime >= 0) {
- this.moodleCourseDataAsyncLoader.setFromCutTime(fromCutTime);
- }
- this.moodleCourseDataAsyncLoader.loadSync(restTemplate);
- courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData().values();
- }
-
- if (courseQuizData.isEmpty()) {
- return Collections.emptyList();
- }
-
- return courseQuizData
- .stream()
- .flatMap(courseData -> quizDataOf(lmsSetup, courseData, urlPrefix).stream())
- .collect(Collectors.toList());
- }
-
private List getQuizzesForIds(
final MoodleAPIRestTemplate restTemplate,
final Set quizIds) {
@@ -672,55 +561,6 @@ public class MoodleCourseAccess implements CourseAccessAPI {
}
}
- private List quizDataOf(
- final LmsSetup lmsSetup,
- final CourseDataShort courseData,
- final String uriPrefix) {
-
- final Map additionalAttrs = new HashMap<>();
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_CREATION_TIME, String.valueOf(courseData.time_created));
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_SHORT_NAME, courseData.short_name);
- additionalAttrs.put(QuizData.ATTR_ADDITIONAL_ID_NUMBER, courseData.idnumber);
-
- final List courseAndQuiz = courseData.quizzes
- .stream()
- .map(courseQuizData -> createQuizData(lmsSetup, courseData, uriPrefix, additionalAttrs, courseQuizData))
- .collect(Collectors.toList());
-
- return courseAndQuiz;
- }
-
- private QuizData createQuizData(
- final LmsSetup lmsSetup,
- final CourseDataShort courseData,
- final String uriPrefix,
- final Map additionalAttrs,
- final CourseQuizShort courseQuizData) {
-
- final String startURI = uriPrefix + courseQuizData.course_module;
- return new QuizData(
- MoodleUtils.getInternalQuizId(
- courseQuizData.course_module, // TODO this is wrong should be id. Create recovery task
- courseData.id,
- courseData.short_name,
- courseData.idnumber),
- lmsSetup.getInstitutionId(),
- lmsSetup.id,
- lmsSetup.getLmsType(),
- (this.prependShortCourseName)
- ? courseData.short_name + " : " + courseQuizData.name
- : courseQuizData.name,
- Constants.EMPTY_NOTE,
- (courseQuizData.time_open != null && courseQuizData.time_open > 0)
- ? Utils.toDateTimeUTCUnix(courseQuizData.time_open)
- : Utils.toDateTimeUTCUnix(courseData.start_date),
- (courseQuizData.time_close != null && courseQuizData.time_close > 0)
- ? Utils.toDateTimeUTCUnix(courseQuizData.time_close)
- : Utils.toDateTimeUTCUnix(courseData.end_date),
- startURI,
- additionalAttrs);
- }
-
private static final void fillSelectedQuizzes(
final Set quizIds,
final Map finalCourseDataRef,
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseDataAsyncLoader.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseDataAsyncLoader.java
deleted file mode 100644
index e3020f26..00000000
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseDataAsyncLoader.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
- *
- * 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.lms.impl.moodle.legacy;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.StringUtils;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.context.annotation.Scope;
-import org.springframework.core.env.Environment;
-import org.springframework.stereotype.Component;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-
-import ch.ethz.seb.sebserver.gbl.Constants;
-import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
-import ch.ethz.seb.sebserver.gbl.async.AsyncRunner;
-import ch.ethz.seb.sebserver.gbl.async.AsyncService;
-import ch.ethz.seb.sebserver.gbl.async.CircuitBreaker;
-import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
-import ch.ethz.seb.sebserver.gbl.util.Utils;
-import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate;
-import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate.Warning;
-import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.CoursePage;
-
-@Lazy
-@Component
-@WebServiceProfile
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-/** This implements the (temporary) asynchronous fetch strategy to fetch
- * course and quiz data within a background task and fill up a shared cache. */
-@Deprecated
-public class MoodleCourseDataAsyncLoader {
-
- private static final Logger log = LoggerFactory.getLogger(MoodleCourseDataAsyncLoader.class);
-
- private final JSONMapper jsonMapper;
- private final AsyncRunner asyncRunner;
- private final CircuitBreaker moodleRestCall;
- private final int maxSize;
- private final int pageSize;
-
- private final Map cachedCourseData = new HashMap<>();
- private final Set newIds = new HashSet<>();
-
- private String lmsSetup = Constants.EMPTY_NOTE;
- private long lastRunTime = 0;
- private long lastLoadTime = 0;
- private boolean running = false;
-
- private long fromCutTime;
-
- public MoodleCourseDataAsyncLoader(
- final JSONMapper jsonMapper,
- final AsyncService asyncService,
- final AsyncRunner asyncRunner,
- final Environment environment) {
-
- this.jsonMapper = jsonMapper;
- final int yearsBeforeNow = environment.getProperty(
- "sebserver.webservice.lms.moodle.fetch.cutoffdate.yearsBeforeNow",
- Integer.class, 3);
- this.fromCutTime = Utils.toUnixTimeInSeconds(DateTime.now(DateTimeZone.UTC).minusYears(yearsBeforeNow));
- this.asyncRunner = asyncRunner;
-
- this.moodleRestCall = asyncService.createCircuitBreaker(
- environment.getProperty(
- "sebserver.webservice.circuitbreaker.moodleRestCall.attempts",
- Integer.class,
- 2),
- environment.getProperty(
- "sebserver.webservice.circuitbreaker.moodleRestCall.blockingTime",
- Long.class,
- Constants.SECOND_IN_MILLIS * 20),
- environment.getProperty(
- "sebserver.webservice.circuitbreaker.moodleRestCall.timeToRecover",
- Long.class,
- Constants.MINUTE_IN_MILLIS));
-
- this.maxSize =
- environment.getProperty("sebserver.webservice.cache.moodle.course.maxSize", Integer.class, 10000);
- this.pageSize =
- environment.getProperty("sebserver.webservice.cache.moodle.course.pageSize", Integer.class, 500);
- }
-
- public void init(final String lmsSetupName) {
- if (Constants.EMPTY_NOTE.equals(this.lmsSetup)) {
- this.lmsSetup = lmsSetupName;
- } else {
- throw new IllegalStateException(
- "Invalid initialization of MoodleCourseDataAsyncLoader. It has already been initialized yet");
- }
- }
-
- public long getFromCutTime() {
- return this.fromCutTime;
- }
-
- public void setFromCutTime(final long fromCutTime) {
- this.fromCutTime = fromCutTime;
- }
-
- public Map getCachedCourseData() {
- return new HashMap<>(this.cachedCourseData);
- }
-
- public long getLastRunTime() {
- return this.lastRunTime;
- }
-
- public boolean isRunning() {
- return this.running;
- }
-
- public boolean isLongRunningTask() {
- return this.lastLoadTime > 3 * Constants.SECOND_IN_MILLIS;
- }
-
- public Map loadSync(final MoodleAPIRestTemplate restTemplate) {
- if (this.running) {
- throw new IllegalStateException("Is already running asynchronously");
- }
-
- this.running = true;
- loadAndCache(restTemplate).run();
- this.lastRunTime = Utils.getMillisecondsNow();
-
- log.info("LMS Setup: {} loaded {} courses synchronously",
- this.lmsSetup,
- this.cachedCourseData.size());
-
- return this.cachedCourseData;
- }
-
- public void loadAsync(final MoodleAPIRestTemplate restTemplate) {
- if (this.running) {
- return;
- }
- this.running = true;
- this.asyncRunner.runAsync(loadAndCache(restTemplate));
- this.lastRunTime = Utils.getMillisecondsNow();
-
- log.info("LMS Setup: {} loaded {} courses asynchronously",
- this.lmsSetup,
- this.cachedCourseData.size());
-
- }
-
- public void clearCache() {
- if (!isRunning()) {
- this.cachedCourseData.clear();
- this.newIds.clear();
- }
- }
-
- private Runnable loadAndCache(final MoodleAPIRestTemplate restTemplate) {
- return () -> {
- this.newIds.clear();
- final long startTime = Utils.getMillisecondsNow();
-
- loadAllQuizzes(restTemplate);
- this.syncCache();
-
- this.lastLoadTime = Utils.getMillisecondsNow() - startTime;
- this.running = false;
- };
- }
-
- private void loadAllQuizzes(final MoodleAPIRestTemplate restTemplate) {
- int page = 0;
- while (getQuizzesBatch(restTemplate, page)) {
- page++;
- }
- }
-
- private boolean getQuizzesBatch(
- final MoodleAPIRestTemplate restTemplate,
- final int page) {
-
- try {
-
- // first get courses from Moodle for page
- final Map courseData = new HashMap<>();
- final Collection coursesPage = getCoursesPage(restTemplate, page, this.pageSize);
-
- if (coursesPage == null || coursesPage.isEmpty()) {
- return false;
- }
-
- courseData.putAll(coursesPage
- .stream()
- .collect(Collectors.toMap(cd -> cd.id, Function.identity())));
-
- // then get all quizzes of courses and filter
- final LinkedMultiValueMap attributes = new LinkedMultiValueMap<>();
- final List courseIds = new ArrayList<>(courseData.keySet());
- if (courseIds.size() == 1) {
- // NOTE: This is a workaround because the Moodle API do not support lists with only one element.
- courseIds.add("0");
- }
- attributes.put(
- MoodleCourseAccess.MOODLE_COURSE_API_COURSE_IDS,
- courseIds);
-
- final String quizzesJSON = callMoodleRestAPI(
- restTemplate,
- MoodleCourseAccess.MOODLE_QUIZ_API_FUNCTION_NAME,
- attributes);
-
- final CourseQuizData courseQuizData = this.jsonMapper.readValue(
- quizzesJSON,
- CourseQuizData.class);
-
- if (courseQuizData == null) {
- // return false; SEBSERV-361
- return true;
- }
-
- if (courseQuizData.warnings != null && !courseQuizData.warnings.isEmpty()) {
- log.warn(
- "There are warnings from Moodle response: Moodle: {} request: {} warnings: {} warning sample: {}",
- this.lmsSetup,
- MoodleCourseAccess.MOODLE_QUIZ_API_FUNCTION_NAME,
- courseQuizData.warnings.size(),
- courseQuizData.warnings.iterator().next().toString());
- if (log.isTraceEnabled()) {
- log.trace("All warnings from Moodle: {}", courseQuizData.warnings.toString());
- }
- }
-
- if (courseQuizData.quizzes == null || courseQuizData.quizzes.isEmpty()) {
- // no quizzes on this page
- return true;
- }
-
- courseQuizData.quizzes
- .stream()
- .filter(getQuizFilter())
- .forEach(quiz -> {
- final CourseDataShort data = courseData.get(quiz.course);
- if (data != null) {
- data.quizzes.add(quiz);
- }
- });
-
- courseData.values().stream()
- .filter(c -> !c.quizzes.isEmpty())
- .forEach(c -> {
- if (this.cachedCourseData.size() >= this.maxSize) {
- log.error(
- "LMS Setup: {} Cache is full and has reached its maximal size. Skip data: -> {}",
- this.lmsSetup,
- c);
- } else {
- this.cachedCourseData.put(c.id, c);
- this.newIds.add(c.id);
- }
- });
-
- return true;
- } catch (final Exception e) {
- log.error("LMS Setup: {} Unexpected exception while trying to get course data: ", this.lmsSetup, e);
- return false;
- }
- }
-
- private Collection getCoursesPage(
- final MoodleAPIRestTemplate restTemplate,
- final int page,
- final int size) throws JsonParseException, JsonMappingException, IOException {
-
- try {
- // get course ids per page
- final LinkedMultiValueMap attributes = new LinkedMultiValueMap<>();
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_SEARCH_CRITERIA_NAME, "search");
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_SEARCH_CRITERIA_VALUE, "");
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_SEARCH_PAGE, String.valueOf(page));
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_SEARCH_PAGE_SIZE, String.valueOf(size));
-
- final String courseKeyPageJSON = callMoodleRestAPI(
- restTemplate,
- MoodleCourseAccess.MOODLE_COURSE_SEARCH_API_FUNCTION_NAME,
- attributes);
-
- final CoursePage keysPage = this.jsonMapper.readValue(
- courseKeyPageJSON,
- CoursePage.class);
-
- if (keysPage == null) {
- log.error("No CoursePage Response");
- return Collections.emptyList();
- }
-
- if (keysPage.warnings != null && !keysPage.warnings.isEmpty()) {
- log.warn(
- "There are warnings from Moodle response: Moodle: {} request: {} warnings: {} warning sample: {}",
- this.lmsSetup,
- MoodleCourseAccess.MOODLE_COURSE_SEARCH_API_FUNCTION_NAME,
- keysPage.warnings.size(),
- keysPage.warnings.iterator().next().toString());
- if (log.isTraceEnabled()) {
- log.trace("All warnings from Moodle: {}", keysPage.warnings.toString());
- }
- }
-
- if (keysPage.courseKeys == null || keysPage.courseKeys.isEmpty()) {
- if (log.isDebugEnabled()) {
- log.debug("LMS Setup: {} No courses found on page: {}", this.lmsSetup, page);
- if (log.isTraceEnabled()) {
- log.trace("Moodle response: {}", courseKeyPageJSON);
- }
- }
- return Collections.emptyList();
- }
-
- // get courses
- final Set ids = keysPage.courseKeys
- .stream()
- .map(key -> key.id)
- .collect(Collectors.toSet());
-
- final Collection result = getCoursesForIds(restTemplate, ids)
- .stream()
- .filter(getCourseFilter())
- .collect(Collectors.toList());
-
- if (log.isDebugEnabled()) {
- log.debug("course page with {} courses, after filtering {} left",
- keysPage.courseKeys.size(),
- result.size());
- }
-
- return result;
- } catch (final Exception e) {
- log.error("LMS Setup: {} Unexpected error while trying to get courses page: ", this.lmsSetup, e);
- return Collections.emptyList();
- }
- }
-
- private Collection getCoursesForIds(
- final MoodleAPIRestTemplate restTemplate,
- final Set ids) {
-
- try {
-
- if (log.isDebugEnabled()) {
- log.debug("LMS Setup: {} Get courses for ids: {}", this.lmsSetup, ids);
- }
-
- final String joinedIds = StringUtils.join(ids, Constants.COMMA);
-
- final LinkedMultiValueMap attributes = new LinkedMultiValueMap<>();
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_FIELD_NAME, MoodleCourseAccess.MOODLE_COURSE_API_IDS);
- attributes.add(MoodleCourseAccess.MOODLE_COURSE_API_FIELD_VALUE, joinedIds);
- final String coursePageJSON = callMoodleRestAPI(
- restTemplate,
- MoodleCourseAccess.MOODLE_COURSE_BY_FIELD_API_FUNCTION_NAME,
- attributes);
-
- final Courses courses = this.jsonMapper.readValue(
- coursePageJSON,
- Courses.class);
-
- if (courses == null) {
- log.error("No Courses response: LMS: {} API call: {}", this.lmsSetup,
- MoodleCourseAccess.MOODLE_COURSE_BY_FIELD_API_FUNCTION_NAME);
- return Collections.emptyList();
- }
-
- if (courses.warnings != null && !courses.warnings.isEmpty()) {
- log.warn(
- "There are warnings from Moodle response: Moodle: {} request: {} warnings: {} warning sample: {}",
- this.lmsSetup,
- MoodleCourseAccess.MOODLE_COURSE_BY_FIELD_API_FUNCTION_NAME,
- courses.warnings.size(),
- courses.warnings.iterator().next().toString());
- if (log.isTraceEnabled()) {
- log.trace("All warnings from Moodle: {}", courses.warnings.toString());
- }
- }
-
- if (courses.courses == null || courses.courses.isEmpty()) {
- log.warn("No courses found for ids: {} on LMS {}", ids, this.lmsSetup);
- return Collections.emptyList();
- }
-
- return courses.courses;
-
- } catch (final Exception e) {
- log.error("LMS Setup: {} Unexpected error while trying to get courses for ids", this.lmsSetup, e);
- return Collections.emptyList();
- }
- }
-
- private String callMoodleRestAPI(
- final MoodleAPIRestTemplate restTemplate,
- final String function,
- final MultiValueMap queryAttributes) {
-
- return this.moodleRestCall
- .protectedRun(() -> restTemplate.callMoodleAPIFunction(
- function,
- queryAttributes))
- .getOrThrow();
-
- }
-
- private Predicate getQuizFilter() {
- final long now = Utils.getSecondsNow();
- return quiz -> {
- if (quiz.time_close == null || quiz.time_close == 0 || quiz.time_close > now) {
- return true;
- }
-
- if (log.isDebugEnabled()) {
- log.debug("LMS Setup: {} remove quiz {} end_time {} now {}",
- this.lmsSetup,
- quiz.name,
- quiz.time_close,
- now);
- }
- return false;
- };
- }
-
- private Predicate getCourseFilter() {
- final long now = Utils.getSecondsNow();
- return course -> {
- if (course.start_date != null && course.start_date < this.fromCutTime) {
- return false;
- }
-
- if (course.end_date == null || course.end_date == 0 || course.end_date > now) {
- return true;
- }
-
- if (log.isDebugEnabled()) {
- log.info("LMS Setup: {} remove course {} end_time {} now {}",
- this.lmsSetup,
- course.short_name,
- course.end_date,
- now);
- }
- return false;
- };
- }
-
- private void syncCache() {
- if (!this.cachedCourseData.isEmpty()) {
-
- final Set oldData = this.cachedCourseData
- .keySet()
- .stream()
- .filter(id -> !this.newIds.contains(id))
- .collect(Collectors.toSet());
-
- synchronized (this.cachedCourseData) {
- oldData.stream().forEach(this.cachedCourseData::remove);
- }
- }
- this.newIds.clear();
- }
-
- /** Maps the Moodle course API course data */
- @JsonIgnoreProperties(ignoreUnknown = true)
- static final class CourseDataShort {
- final String id;
- final String short_name;
- final String idnumber;
- final Long start_date; // unix-time seconds UTC
- final Long end_date; // unix-time seconds UTC
- final Long time_created; // unix-time seconds UTC
- final Collection quizzes = new ArrayList<>();
-
- @JsonCreator
- protected CourseDataShort(
- @JsonProperty(value = "id") final String id,
- @JsonProperty(value = "shortname") final String short_name,
- @JsonProperty(value = "idnumber") final String idnumber,
- @JsonProperty(value = "startdate") final Long start_date,
- @JsonProperty(value = "enddate") final Long end_date,
- @JsonProperty(value = "timecreated") final Long time_created) {
-
- this.id = id;
- this.short_name = short_name;
- this.idnumber = idnumber;
- this.start_date = start_date;
- this.end_date = end_date;
- this.time_created = time_created;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final CourseDataShort other = (CourseDataShort) obj;
- if (this.id == null) {
- if (other.id != null)
- return false;
- } else if (!this.id.equals(other.id))
- return false;
- return true;
- }
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- private static final class Courses {
- final Collection courses;
- final Collection warnings;
-
- @JsonCreator
- protected Courses(
- @JsonProperty(value = "courses") final Collection courses,
- @JsonProperty(value = "warnings") final Collection warnings) {
- this.courses = courses;
- this.warnings = warnings;
- }
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- static final class CourseQuizData {
- final Collection quizzes;
- final Collection warnings;
-
- @JsonCreator
- protected CourseQuizData(
- @JsonProperty(value = "quizzes") final Collection quizzes,
- @JsonProperty(value = "warnings") final Collection warnings) {
- this.quizzes = quizzes;
- this.warnings = warnings;
- }
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- static final class CourseQuizShort {
- final String id;
- final String course;
- final String course_module;
- final String name;
- final Long time_open; // unix-time seconds UTC
- final Long time_close; // unix-time seconds UTC
-
- @JsonCreator
- protected CourseQuizShort(
- @JsonProperty(value = "id") final String id,
- @JsonProperty(value = "course") final String course,
- @JsonProperty(value = "coursemodule") final String course_module,
- @JsonProperty(value = "name") final String name,
- @JsonProperty(value = "timeopen") final Long time_open,
- @JsonProperty(value = "timeclose") final Long time_close) {
-
- this.id = id;
- this.course = course;
- this.course_module = course_module;
- this.name = name;
- this.time_open = time_open;
- this.time_close = time_close;
- }
- }
-
-}
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleLmsAPITemplateFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleLmsAPITemplateFactory.java
index 8c21f7c1..c8764c7c 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleLmsAPITemplateFactory.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleLmsAPITemplateFactory.java
@@ -20,7 +20,6 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.async.AsyncService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
-import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
@@ -43,7 +42,6 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
private final Environment environment;
private final ClientCredentialService clientCredentialService;
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
- private final ApplicationContext applicationContext;
private final String[] alternativeTokenRequestPaths;
protected MoodleLmsAPITemplateFactory(
@@ -60,7 +58,6 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
this.environment = environment;
this.clientCredentialService = clientCredentialService;
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
- this.applicationContext = applicationContext;
this.alternativeTokenRequestPaths = (alternativeTokenRequestPaths != null)
? StringUtils.split(alternativeTokenRequestPaths, Constants.LIST_SEPARATOR)
: null;
@@ -76,11 +73,6 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
return Result.tryCatch(() -> {
- final LmsSetup lmsSetup = apiTemplateDataSupplier.getLmsSetup();
- final MoodleCourseDataAsyncLoader asyncLoaderPrototype = this.applicationContext
- .getBean(MoodleCourseDataAsyncLoader.class);
- asyncLoaderPrototype.init(lmsSetup.getModelId());
-
final MoodleRestTemplateFactory restTemplateFactory = new MoodleRestTemplateFactoryImpl(
this.jsonMapper,
apiTemplateDataSupplier,
@@ -92,7 +84,6 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
this.jsonMapper,
this.asyncService,
restTemplateFactory,
- asyncLoaderPrototype,
this.environment);
return new LmsAPITemplateAdapter(
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseAccess.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseAccess.java
index 2e3a464e..865d2f73 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseAccess.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MoodlePluginCourseAccess.java
@@ -168,11 +168,6 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme
return LmsSetupTestResult.ofOkay(LmsType.MOODLE_PLUGIN);
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return Result.ofError(new UnsupportedOperationException());
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
try {
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java
index 917ba0bc..c682527f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/olat/OlatLmsAPITemplate.java
@@ -170,15 +170,6 @@ public class OlatLmsAPITemplate extends AbstractCachedCourseAccess implements Lm
return LmsSetupTestResult.ofOkay(LmsType.OPEN_OLAT);
}
- @Override
- public Result> getQuizzes(final FilterMap filterMap) {
- return this
- .allQuizzesRequest(filterMap)
- .map(quizzes -> quizzes.stream()
- .filter(LmsAPIService.quizFilterPredicate(filterMap))
- .collect(Collectors.toList()));
- }
-
@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
this.allQuizzesRequest(filterMap)
diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccessTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccessTest.java
index 920b611e..1aff5826 100644
--- a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccessTest.java
+++ b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/legacy/MoodleCourseAccessTest.java
@@ -80,7 +80,6 @@ public class MoodleCourseAccessTest {
new JSONMapper(),
this.asyncService,
moodleRestTemplateFactory,
- null,
this.env);
final String examId = "123";
@@ -129,7 +128,6 @@ public class MoodleCourseAccessTest {
new JSONMapper(),
this.asyncService,
moodleRestTemplateFactory,
- null,
this.env);
final LmsSetupTestResult initAPIAccess = moodleCourseAccess.testCourseAccessAPI();
@@ -152,7 +150,6 @@ public class MoodleCourseAccessTest {
new JSONMapper(),
this.asyncService,
moodleRestTemplateFactory,
- null,
this.env);
final LmsSetupTestResult initAPIAccess = moodleCourseAccess.testCourseAccessAPI();
@@ -174,7 +171,6 @@ public class MoodleCourseAccessTest {
new JSONMapper(),
this.asyncService,
moodleRestTemplateFactory,
- null,
this.env);
final LmsSetupTestResult initAPIAccess = moodleCourseAccess.testCourseAccessAPI();