Skip to content

Commit

Permalink
SEBSERV-413 removed old LMS Setup code (async loader Moodle)
Browse files Browse the repository at this point in the history
  • Loading branch information
anhefti committed May 15, 2023
1 parent bf6aa19 commit 7c42974
Show file tree
Hide file tree
Showing 11 changed files with 1 addition and 895 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
Expand Down Expand Up @@ -52,20 +51,6 @@ default void checkCourseAPIAccess() {
}
}

/** 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:
*
* <pre>
* {@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)
* </pre>
*
* @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<List<QuizData>> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -221,26 +220,6 @@ public LmsSetupTestResult testCourseAccessAPI() {
return LmsSetupTestResult.ofAPINotSupported(getType());
}

@Override
@Deprecated
public Result<List<QuizData>> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,6 @@ private LmsSetupTestResult testLmsSetupSettings() {
return LmsSetupTestResult.ofOkay(LmsType.ANS_DELFT);
}

@Override
public Result<List<QuizData>> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,6 @@ public LmsSetupTestResult testCourseAccessAPI() {
return LmsSetupTestResult.ofOkay(LmsType.OPEN_EDX);
}

@Override
public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
return getRestTemplate().map(this::collectAllQuizzes);
}

@Override
public void fetchQuizzes(final FilterMap filterMap, final AsyncQuizFetchBuffer asyncQuizFetchBuffer) {
try {
Expand Down Expand Up @@ -360,25 +355,6 @@ private ArrayList<QuizData> collectQuizzes(final OAuth2RestTemplate restTemplate
});
}

private ArrayList<QuizData> 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;
Expand Down Expand Up @@ -466,22 +442,6 @@ private CourseData getOneCourse(
}
}

private List<CourseData> collectAllCourses(final String pageURI, final OAuth2RestTemplate restTemplate) {
final List<CourseData> 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<EdXPage> getEdxPage(final String pageURI, final OAuth2RestTemplate restTemplate) {
final HttpHeaders httpHeaders = new HttpHeaders();
return restTemplate.exchange(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,27 +160,6 @@ private List<APIMessage> checkAttributes() {
return missingAttrs;
}

@Override
public Result<List<QuizData>> 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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

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;
Expand Down Expand Up @@ -59,8 +58,6 @@
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.
*
Expand All @@ -78,7 +75,7 @@
* 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);

Expand All @@ -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<String> protectedMoodlePageCall;
private final int pageSize;
Expand All @@ -113,11 +109,9 @@ public MoodleCourseAccess(
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(
Expand Down Expand Up @@ -176,16 +170,6 @@ public LmsSetupTestResult testCourseAccessAPI() {
return LmsSetupTestResult.ofOkay(LmsType.MOODLE);
}

@Override
public Result<List<QuizData>> 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 {
Expand Down Expand Up @@ -297,35 +281,6 @@ public Result<Collection<QuizData>> getQuizzes(final Set<String> ids) {
@Override
public Result<QuizData> getQuiz(final String id) {
return Result.tryCatch(() -> {

final Map<String, CourseDataShort> 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<String, String> 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<String> ids = Stream.of(id).collect(Collectors.toSet());
return getRestTemplate()
Expand Down Expand Up @@ -475,72 +430,6 @@ public Result<Chapters> getCourseChapters(final String courseId) {
return Result.ofError(new UnsupportedOperationException("not available yet"));
}

public void clearCache() {
this.moodleCourseDataAsyncLoader.clearCache();
}

private List<QuizData> 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<CourseDataShort> 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<QuizData> getQuizzesForIds(
final MoodleAPIRestTemplate restTemplate,
final Set<String> quizIds) {
Expand Down Expand Up @@ -672,55 +561,6 @@ private Collection<CourseData> getCoursesForIds(
}
}

private List<QuizData> quizDataOf(
final LmsSetup lmsSetup,
final CourseDataShort courseData,
final String uriPrefix) {

final Map<String, String> 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<QuizData> 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<String, String> 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<String> quizIds,
final Map<String, CourseData> finalCourseDataRef,
Expand Down
Loading

0 comments on commit 7c42974

Please sign in to comment.