diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTestResult.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTestResult.java index fbef5775..b014fbf3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTestResult.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTestResult.java @@ -32,7 +32,8 @@ public final class LmsSetupTestResult { MISSING_ATTRIBUTE, TOKEN_REQUEST, QUIZ_ACCESS_API_REQUEST, - QUIZ_RESTRICTION_API_REQUEST + QUIZ_RESTRICTION_API_REQUEST, + TEMPLATE_CREATION } @JsonProperty(Domain.LMS_SETUP.ATTR_LMS_TYPE) @@ -59,7 +60,7 @@ public final class LmsSetupTestResult { Collections.emptyList()); } - protected LmsSetupTestResult(final LmsSetup.LmsType lmsType, final Error error) { + public LmsSetupTestResult(final LmsSetup.LmsType lmsType, final Error error) { this(lmsType, Utils.immutableCollectionOf(Arrays.asList(error)), Collections.emptyList()); @@ -163,7 +164,6 @@ public final class LmsSetupTestResult { builder.append("]"); return builder.toString(); } - } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/LmsSetupForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/LmsSetupForm.java index 8b7325aa..e01f76ee 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/LmsSetupForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/LmsSetupForm.java @@ -479,6 +479,11 @@ public class LmsSetupForm implements TemplateComposer { Utils.formatHTMLLinesForceEscaped(Utils.escapeHTML_XML_EcmaScript(error.message)))); } case QUIZ_ACCESS_API_REQUEST: { + if (error.message.contains("quizaccess_sebserver_get_exams")) { + throw new PageMessageException(new LocTextKey( + "sebserver.lmssetup.action.test.quizRequestError.moodle.missing.plugin", + Utils.formatHTMLLinesForceEscaped(Utils.escapeHTML_XML_EcmaScript(error.message)))); + } throw new PageMessageException(new LocTextKey( "sebserver.lmssetup.action.test.quizRequestError", Utils.formatHTMLLinesForceEscaped(Utils.escapeHTML_XML_EcmaScript(error.message)))); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPIServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPIServiceImpl.java index 822a8b50..852ba305 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPIServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/LmsAPIServiceImpl.java @@ -24,7 +24,6 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.client.ProxyData; @@ -33,12 +32,12 @@ import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; 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.model.institution.LmsSetupTestResult; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult.ErrorType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO; -import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; @@ -133,17 +132,13 @@ public class LmsAPIServiceImpl implements LmsAPIService { public Result getLmsAPITemplate(final String lmsSetupId) { return Result.tryCatch(() -> { synchronized (this) { - LmsAPITemplate lmsAPITemplate = getFromCache(lmsSetupId); + final LmsAPITemplate lmsAPITemplate = getFromCache(lmsSetupId); if (lmsAPITemplate == null) { - lmsAPITemplate = createLmsSetupTemplate(lmsSetupId); - if (lmsAPITemplate != null) { - this.cache.put(new CacheKey(lmsSetupId, System.currentTimeMillis()), lmsAPITemplate); - } + return createLmsSetupTemplate(lmsSetupId) + .onError(error -> log.error("Failed to create LMSSetup: ", error)) + .onSuccess(t -> this.cache.put(new CacheKey(lmsSetupId, System.currentTimeMillis()), t)) + .getOrThrow(); } - if (lmsAPITemplate == null) { - throw new ResourceNotFoundException(EntityType.LMS_SETUP, lmsSetupId); - } - return lmsAPITemplate; } }); @@ -153,10 +148,12 @@ public class LmsAPIServiceImpl implements LmsAPIService { public LmsSetupTestResult test(final LmsAPITemplate template) { final LmsSetupTestResult testCourseAccessAPI = template.testCourseAccessAPI(); if (!testCourseAccessAPI.isOk()) { + this.cache.remove(new CacheKey(template.lmsSetup().getModelId(), 0)); return testCourseAccessAPI; } if (template.lmsSetup().getLmsType().features.contains(LmsSetup.Features.SEB_RESTRICTION)) { + this.cache.remove(new CacheKey(template.lmsSetup().getModelId(), 0)); return template.testCourseRestrictionAPI(); } @@ -169,7 +166,15 @@ public class LmsAPIServiceImpl implements LmsAPIService { lmsSetup, this.clientCredentialService); - final LmsAPITemplate lmsSetupTemplate = createLmsSetupTemplate(apiTemplateDataSupplier); + final Result createLmsSetupTemplate = createLmsSetupTemplate(apiTemplateDataSupplier); + if (createLmsSetupTemplate.hasError()) { + return new LmsSetupTestResult( + lmsSetup.lmsType, + new LmsSetupTestResult.Error(ErrorType.TEMPLATE_CREATION, + createLmsSetupTemplate.getError().getMessage())); + + } + final LmsAPITemplate lmsSetupTemplate = createLmsSetupTemplate.get(); final LmsSetupTestResult testCourseAccessAPI = lmsSetupTemplate.testCourseAccessAPI(); if (!testCourseAccessAPI.isOk()) { @@ -183,40 +188,6 @@ public class LmsAPIServiceImpl implements LmsAPIService { return LmsSetupTestResult.ofOkay(lmsSetupTemplate.lmsSetup().getLmsType()); } -// /** Collect all QuizData from all affecting LmsSetup. -// * If filterMap contains a LmsSetup identifier, only the QuizData from that LmsSetup is collected. -// * Otherwise QuizData from all active LmsSetup of the current institution are collected. -// * -// * @param filterMap the FilterMap containing either an LmsSetup identifier or an institution identifier -// * @return list of QuizData from all affecting LmsSetup */ -// private Result> getAllQuizzesFromLMSSetups(final FilterMap filterMap) { -// -// // case 1. if lmsSetupId is available only get quizzes from specified LmsSetup -// final Long lmsSetupId = filterMap.getLmsSetupId(); -// if (lmsSetupId != null) { -// return getQuizzesForSingleLMS(filterMap, lmsSetupId); -// } -// -// // case 2. get quizzes from all LmsSetups of specified institution -// return this.quizLookupService.getAllQuizzesFromLMSSetups( -// filterMap, -// this::getLmsAPITemplate); -// -//// final Long institutionId = filterMap.getInstitutionId(); -//// return this.lmsSetupDAO.all(institutionId, true) -//// .getOrThrow() -//// .parallelStream() -//// .map(LmsSetup::getModelId) -//// .map(this::getLmsAPITemplate) -//// .flatMap(Result::onErrorLogAndSkip) -//// .map(template -> template.getQuizzes(filterMap)) -//// .flatMap(Result::onErrorLogAndSkip) -//// .flatMap(List::stream) -//// .distinct() -//// .collect(Collectors.toList()); -// -// } - private LmsAPITemplate getFromCache(final String lmsSetupId) { // first cleanup the cache by removing old instances final long currentTimeMillis = System.currentTimeMillis(); @@ -245,7 +216,7 @@ public class LmsAPIServiceImpl implements LmsAPIService { return lmsAPITemplate; } - private LmsAPITemplate createLmsSetupTemplate(final String lmsSetupId) { + private Result createLmsSetupTemplate(final String lmsSetupId) { if (log.isDebugEnabled()) { log.debug("Create new LmsAPITemplate for id: {}", lmsSetupId); @@ -256,7 +227,7 @@ public class LmsAPIServiceImpl implements LmsAPIService { this.lmsSetupDAO)); } - private LmsAPITemplate createLmsSetupTemplate(final APITemplateDataSupplier apiTemplateDataSupplier) { + private Result createLmsSetupTemplate(final APITemplateDataSupplier apiTemplateDataSupplier) { final LmsType lmsType = apiTemplateDataSupplier.getLmsSetup().lmsType; @@ -268,8 +239,7 @@ public class LmsAPIServiceImpl implements LmsAPIService { .get(lmsType); return lmsAPITemplateFactory - .create(apiTemplateDataSupplier) - .getOrThrow(); + .create(apiTemplateDataSupplier); } /** Used to always get the actual LMS connection data from persistent */ diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MockupRestTemplateFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MockupRestTemplateFactory.java deleted file mode 100644 index 4cf512e0..00000000 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MockupRestTemplateFactory.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2022 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; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponentsBuilder; - -import com.fasterxml.jackson.core.JsonProcessingException; - -import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.api.JSONMapper; -import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; -import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult; -import ch.ethz.seb.sebserver.gbl.util.Result; -import ch.ethz.seb.sebserver.gbl.util.Utils; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleUtils.MoodleQuizRestriction; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseAccess; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseRestriction; - -@Deprecated -public class MockupRestTemplateFactory implements MoodleRestTemplateFactory { - - private final APITemplateDataSupplier apiTemplateDataSupplier; - - public MockupRestTemplateFactory(final APITemplateDataSupplier apiTemplateDataSupplier) { - this.apiTemplateDataSupplier = apiTemplateDataSupplier; - } - - @Override - public LmsSetupTestResult test() { - return LmsSetupTestResult.ofOkay(LmsType.MOODLE_PLUGIN); - } - - @Override - public APITemplateDataSupplier getApiTemplateDataSupplier() { - return this.apiTemplateDataSupplier; - } - - @Override - public Set getKnownTokenAccessPaths() { - final Set paths = new HashSet<>(); - paths.add(MoodleAPIRestTemplate.MOODLE_DEFAULT_TOKEN_REQUEST_PATH); - return paths; - } - - @Override - public Result createRestTemplate() { - return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl)); - } - - @Override - public Result createRestTemplate(final String accessTokenPath) { - return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl)); - } - - public static final class MockupMoodleRestTemplate implements MoodleAPIRestTemplate { - - private final String accessToken = UUID.randomUUID().toString(); - private final String url; - - public MockupMoodleRestTemplate(final String url) { - this.url = url; - } - - @Override - public String getService() { - return "mockup-service"; - } - - @Override - public void setService(final String service) { - } - - @Override - public CharSequence getAccessToken() { - System.out.println("***** getAccessToken: " + this.accessToken); - return this.accessToken; - } - - @Override - public void testAPIConnection(final String... functions) { - System.out.println("***** testAPIConnection functions: " + functions); - } - - @Override - public String callMoodleAPIFunction(final String functionName) { - return callMoodleAPIFunction(functionName, null, null); - } - - @Override - public String callMoodleAPIFunction( - final String functionName, - final MultiValueMap queryAttributes) { - return callMoodleAPIFunction(functionName, null, queryAttributes); - } - - @Override - public String callMoodleAPIFunction( - final String functionName, - final MultiValueMap queryParams, - final MultiValueMap queryAttributes) { - - final UriComponentsBuilder queryParam = UriComponentsBuilder - .fromHttpUrl(this.url + MOODLE_DEFAULT_REST_API_PATH) - .queryParam(REST_REQUEST_TOKEN_NAME, this.accessToken) - .queryParam(REST_REQUEST_FUNCTION_NAME, functionName) - .queryParam(REST_REQUEST_FORMAT_NAME, "json"); - - if (queryParams != null && !queryParams.isEmpty()) { - queryParam.queryParams(queryParams); - } - - final boolean usePOST = queryAttributes != null && !queryAttributes.isEmpty(); - HttpEntity functionReqEntity; - if (usePOST) { - final HttpHeaders headers = new HttpHeaders(); - headers.set( - HttpHeaders.CONTENT_TYPE, - MediaType.APPLICATION_FORM_URLENCODED_VALUE); - - final String body = Utils.toAppFormUrlEncodedBody(queryAttributes); - functionReqEntity = new HttpEntity<>(body, headers); - - } else { - functionReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>()); - } - - System.out.println("***** callMoodleAPIFunction HttpEntity: " + functionReqEntity); - - if (MoodlePluginCourseAccess.COURSES_API_FUNCTION_NAME.equals(functionName)) { - return respondCourses(queryAttributes); - } else if (MoodlePluginCourseAccess.USERS_API_FUNCTION_NAME.equals(functionName)) { - return respondUsers(queryAttributes); - } else if (MoodlePluginCourseRestriction.RESTRICTION_GET_FUNCTION_NAME.equals(functionName)) { - - return respondGetRestriction( - queryParams.getFirst(MoodlePluginCourseRestriction.ATTRIBUTE_QUIZ_ID), - queryAttributes); - } else if (MoodlePluginCourseRestriction.RESTRICTION_SET_FUNCTION_NAME.equals(functionName)) { - return respondSetRestriction( - queryParams.getFirst(MoodlePluginCourseRestriction.ATTRIBUTE_QUIZ_ID), - queryAttributes); - } - - else { - throw new RuntimeException("Unknown function: " + functionName); - } - } - - @SuppressWarnings("unused") - private static final class MockCD { - public final String id; - public final String shortname; - public final String categoryid; - public final String fullname; - public final String displayname; - public final String idnumber; - public final Long startdate; // unix-time seconds UTC - public final Long enddate; // unix-time seconds UTC - public final Long timecreated; // unix-time seconds UTC - public final boolean visible; - public final Collection quizzes; - - public MockCD(final String num, final Collection quizzes) { - this.id = num; - this.shortname = "c" + num; - this.categoryid = "mock"; - this.fullname = "course" + num; - this.displayname = this.fullname; - this.idnumber = "i" + num; - this.startdate = Long.valueOf(num); - this.enddate = null; - this.timecreated = Long.valueOf(num); - this.visible = true; - this.quizzes = quizzes; - } - } - - @SuppressWarnings("unused") - private static final class MockQ { - public final String id; - public final String coursemodule; - public final String course; - public final String name; - public final String intro; - public final Long timeopen; // unix-time seconds UTC - public final Long timeclose; // unix-time seconds UTC - - public MockQ(final String courseId, final String num) { - this.id = num; - this.coursemodule = courseId; - this.course = courseId; - this.name = "quiz " + num; - this.intro = this.name; - this.timeopen = Long.valueOf(num); - this.timeclose = null; - } - } - - private String respondCourses(final MultiValueMap queryAttributes) { - try { - final List ids = queryAttributes.get(MoodlePluginCourseAccess.PARAM_COURSE_ID); - final String from = queryAttributes.getFirst(MoodlePluginCourseAccess.PARAM_PAGE_START); - System.out.println("************* from: " + from); - final List courses; - if (ids != null && !ids.isEmpty()) { - courses = ids - .stream() - .map(id -> new MockCD( - id, - getQuizzesForCourse(Integer.parseInt(id)))) - .collect(Collectors.toList()); - } else if (from != null && Integer.valueOf(from) < 11) { - courses = new ArrayList<>(); - final int num = (Integer.valueOf(from) > 0) ? 10 : 1; - for (int i = 0; i < 10; i++) { - courses.add(new MockCD(String.valueOf(num + i), getQuizzesForCourse(num + i))); - } - } else { - courses = new ArrayList<>(); - } - - final Map response = new HashMap<>(); - response.put("results", courses); - final JSONMapper jsonMapper = new JSONMapper(); - final String result = jsonMapper.writeValueAsString(response); - System.out.println("******** courses response: " + result); - return result; - } catch (final JsonProcessingException e) { - e.printStackTrace(); - return ""; - } - } - - private final Map restrcitions = new HashMap<>(); - - private String respondSetRestriction(final String quizId, final MultiValueMap queryAttributes) { - final List configKeys = queryAttributes.get(MoodlePluginCourseRestriction.ATTRIBUTE_CONFIG_KEYS); - final List beks = queryAttributes.get(MoodlePluginCourseRestriction.ATTRIBUTE_BROWSER_EXAM_KEYS); - final String quitURL = queryAttributes.getFirst(MoodlePluginCourseRestriction.ATTRIBUTE_QUIT_URL); - final String quitSecret = queryAttributes.getFirst(MoodlePluginCourseRestriction.ATTRIBUTE_QUIT_SECRET); - - final MoodleQuizRestriction moodleQuizRestriction = new MoodleQuizRestriction( - quizId, - StringUtils.join(configKeys, Constants.LIST_SEPARATOR), - StringUtils.join(beks, Constants.LIST_SEPARATOR), - quitURL, - quitSecret); - this.restrcitions.put(quizId, moodleQuizRestriction); - - final JSONMapper jsonMapper = new JSONMapper(); - try { - return jsonMapper.writeValueAsString(moodleQuizRestriction); - } catch (final JsonProcessingException e) { - e.printStackTrace(); - return ""; - } - } - - private String respondGetRestriction(final String quizId, final MultiValueMap queryAttributes) { - final MoodleQuizRestriction moodleQuizRestriction = this.restrcitions.get(quizId); - if (moodleQuizRestriction != null) { - final JSONMapper jsonMapper = new JSONMapper(); - try { - return jsonMapper.writeValueAsString(moodleQuizRestriction); - } catch (final JsonProcessingException e) { - e.printStackTrace(); - return ""; - } - } - return ""; - } - - private Collection getQuizzesForCourse(final int courseId) { - final String id = String.valueOf(courseId); - final Collection result = new ArrayList<>(); - result.add(new MockQ(id, "10" + id)); - if (courseId % 2 > 0) { - result.add(new MockQ(id, "11" + id)); - } - - return result; - } - - private String respondUsers(final MultiValueMap queryAttributes) { - // TODO - return ""; - } - - } -} 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 b0af057f..ff15d935 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 @@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; -import org.springframework.cache.CacheManager; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Lazy; import org.springframework.core.env.Environment; @@ -25,52 +24,39 @@ 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; -import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamConfigurationValueService; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsAPITemplateAdapter; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodlePluginCheck; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactoryImpl; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseAccess; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseRestriction; @Lazy @Service @WebServiceProfile public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory { - private final MoodlePluginCheck moodlePluginCheck; private final JSONMapper jsonMapper; - private final CacheManager cacheManager; private final AsyncService asyncService; private final Environment environment; private final ClientCredentialService clientCredentialService; private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; - private final ExamConfigurationValueService examConfigurationValueService; private final ApplicationContext applicationContext; private final String[] alternativeTokenRequestPaths; protected MoodleLmsAPITemplateFactory( - final MoodlePluginCheck moodlePluginCheck, final JSONMapper jsonMapper, - final CacheManager cacheManager, final AsyncService asyncService, final Environment environment, final ClientCredentialService clientCredentialService, - final ExamConfigurationValueService examConfigurationValueService, final ClientHttpRequestFactoryService clientHttpRequestFactoryService, final ApplicationContext applicationContext, @Value("${sebserver.webservice.lms.moodle.api.token.request.paths:}") final String alternativeTokenRequestPaths) { - this.moodlePluginCheck = moodlePluginCheck; this.jsonMapper = jsonMapper; - this.cacheManager = cacheManager; this.asyncService = asyncService; this.environment = environment; this.clientCredentialService = clientCredentialService; - this.examConfigurationValueService = examConfigurationValueService; this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; this.applicationContext = applicationContext; this.alternativeTokenRequestPaths = (alternativeTokenRequestPaths != null) @@ -100,43 +86,20 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory { this.clientHttpRequestFactoryService, this.alternativeTokenRequestPaths); - if (this.moodlePluginCheck.checkPluginAvailable(restTemplateFactory)) { + final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess( + this.jsonMapper, + this.asyncService, + restTemplateFactory, + asyncLoaderPrototype, + this.environment); - final MoodlePluginCourseAccess moodlePluginCourseAccess = new MoodlePluginCourseAccess( - this.jsonMapper, - this.asyncService, - restTemplateFactory, - this.cacheManager, - this.environment); + return new LmsAPITemplateAdapter( + this.asyncService, + this.environment, + apiTemplateDataSupplier, + moodleCourseAccess, + new MoodleCourseRestriction()); - final MoodlePluginCourseRestriction moodlePluginCourseRestriction = new MoodlePluginCourseRestriction( - this.jsonMapper, - restTemplateFactory, - this.examConfigurationValueService); - - return new LmsAPITemplateAdapter( - this.asyncService, - this.environment, - apiTemplateDataSupplier, - moodlePluginCourseAccess, - moodlePluginCourseRestriction); - - } else { - - final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess( - this.jsonMapper, - this.asyncService, - restTemplateFactory, - asyncLoaderPrototype, - this.environment); - - return new LmsAPITemplateAdapter( - this.asyncService, - this.environment, - apiTemplateDataSupplier, - moodleCourseAccess, - new MoodleCourseRestriction()); - } }); } 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 c3b4aecd..3bc16789 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 @@ -160,7 +160,6 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme USERS_API_FUNCTION_NAME); } catch (final RuntimeException e) { - log.error("Failed to access Moodle course API: ", e); return LmsSetupTestResult.ofQuizAccessAPIError(LmsType.MOODLE_PLUGIN, e.getMessage()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MooldePluginLmsAPITemplateFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MooldePluginLmsAPITemplateFactory.java index 3c72b893..09d16a5e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MooldePluginLmsAPITemplateFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/plugin/MooldePluginLmsAPITemplateFactory.java @@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Lazy; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @@ -29,9 +28,9 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.LmsAPITemplateAdapter; -import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MockupRestTemplateFactory; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodlePluginCheck; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory; +import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactoryImpl; @Lazy @Service @@ -46,7 +45,6 @@ public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory private final ClientCredentialService clientCredentialService; private final ExamConfigurationValueService examConfigurationValueService; private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; - private final ApplicationContext applicationContext; private final String[] alternativeTokenRequestPaths; protected MooldePluginLmsAPITemplateFactory( @@ -58,7 +56,6 @@ public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory final ClientCredentialService clientCredentialService, final ExamConfigurationValueService examConfigurationValueService, final ClientHttpRequestFactoryService clientHttpRequestFactoryService, - final ApplicationContext applicationContext, @Value("${sebserver.webservice.lms.moodle.api.token.request.paths:}") final String alternativeTokenRequestPaths) { this.moodlePluginCheck = moodlePluginCheck; @@ -69,7 +66,6 @@ public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory this.clientCredentialService = clientCredentialService; this.examConfigurationValueService = examConfigurationValueService; this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; - this.applicationContext = applicationContext; this.alternativeTokenRequestPaths = (alternativeTokenRequestPaths != null) ? StringUtils.split(alternativeTokenRequestPaths, Constants.LIST_SEPARATOR) : null; @@ -84,15 +80,16 @@ public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory public Result create(final APITemplateDataSupplier apiTemplateDataSupplier) { return Result.tryCatch(() -> { -// final MoodleRestTemplateFactory moodleRestTemplateFactory = new MoodleRestTemplateFactoryImpl( -// this.jsonMapper, -// apiTemplateDataSupplier, -// this.clientCredentialService, -// this.clientHttpRequestFactoryService, -// this.alternativeTokenRequestPaths); + final MoodleRestTemplateFactory moodleRestTemplateFactory = new MoodleRestTemplateFactoryImpl( + this.jsonMapper, + apiTemplateDataSupplier, + this.clientCredentialService, + this.clientHttpRequestFactoryService, + this.alternativeTokenRequestPaths); - final MoodleRestTemplateFactory moodleRestTemplateFactory = - new MockupRestTemplateFactory(apiTemplateDataSupplier); +// if (!this.moodlePluginCheck.checkPluginAvailable(moodleRestTemplateFactory)) { +// throw new RuntimeException("Unable to detect SEB Server Moodle integration plugin!"); +// } final MoodlePluginCourseAccess moodlePluginCourseAccess = new MoodlePluginCourseAccess( this.jsonMapper, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java index 73510c53..1a79851e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LmsSetupController.java @@ -28,7 +28,9 @@ import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Entity; 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.model.institution.LmsSetupTestResult; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult.ErrorType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordDynamicSqlSupport; @@ -93,9 +95,16 @@ public class LmsSetupController extends ActivatableEntityController { + final LmsType lmsType = this.entityDAO.byPK(modelId).get().lmsType; + return new LmsSetupTestResult( + lmsType, + new LmsSetupTestResult.Error(ErrorType.TEMPLATE_CREATION, error.getMessage())); + }) + .get(); if (result.missingLMSSetupAttribute != null && !result.missingLMSSetupAttribute.isEmpty()) { throw new APIMessageException(result.missingLMSSetupAttribute); diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index e90793bb..4905fee1 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -328,6 +328,8 @@ sebserver.useraccount.delete.confirm.message.noDeps=The User Account ({0}) was s sebserver.lmssetup.type.MOCKUP=Testing sebserver.lmssetup.type.MOODLE=Moodle +sebserver.lmssetup.type.MOODLE_PLUGIN=Moodle Plugin +sebserver.lmssetup.type.MOODLE_PLUGIN.tooltip=Moodle with SEB Server integration plugin installed sebserver.lmssetup.type.OPEN_EDX=Open edX sebserver.lmssetup.type.ANS_DELFT=Ans Delft sebserver.lmssetup.type.OPEN_OLAT=Open OLAT @@ -365,6 +367,7 @@ sebserver.lmssetup.action.test.quizRestrictionError=Unable to access course rest sebserver.lmssetup.action.test.features.error=The API access was granted but there is some missing functionality:

- Course Access: {0}
- SEB Restriction: {1} sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.
Please check the connection parameter for this LMS Setup sebserver.lmssetup.action.test.unknownError=An unexpected error happened while trying to connect to the LMS course API. {0} +sebserver.lmssetup.action.test.quizRequestError.moodle.missing.plugin=Moodle SEB Server integration plugin cannot be detected on this Moodle server.
Please consider using the origin "Moodle" LMS Setup type or install the SEB Server integration plugin on this Moodle server.

For further information please refer to the documentation sebserver.lmssetup.action.save=Save LMS Setup sebserver.lmssetup.action.activate=Activate LMS Setup sebserver.lmssetup.action.deactivate=Deactivate LMS Setup