SEBSERV-301 moved mockup to test and improved LMSSetup test function

This commit is contained in:
anhefti 2023-01-12 08:04:40 +01:00
parent 3a86db9ba0
commit ed180603f8
9 changed files with 64 additions and 431 deletions

View file

@ -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();
}
}
}

View file

@ -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))));

View file

@ -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<LmsAPITemplate> 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<LmsAPITemplate> 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<List<QuizData>> 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<LmsAPITemplate> 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<LmsAPITemplate> 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 */

View file

@ -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<String> getKnownTokenAccessPaths() {
final Set<String> paths = new HashSet<>();
paths.add(MoodleAPIRestTemplate.MOODLE_DEFAULT_TOKEN_REQUEST_PATH);
return paths;
}
@Override
public Result<MoodleAPIRestTemplate> createRestTemplate() {
return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl));
}
@Override
public Result<MoodleAPIRestTemplate> 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<String, String> queryAttributes) {
return callMoodleAPIFunction(functionName, null, queryAttributes);
}
@Override
public String callMoodleAPIFunction(
final String functionName,
final MultiValueMap<String, String> queryParams,
final MultiValueMap<String, String> 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<MockQ> quizzes;
public MockCD(final String num, final Collection<MockQ> 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<String, String> queryAttributes) {
try {
final List<String> ids = queryAttributes.get(MoodlePluginCourseAccess.PARAM_COURSE_ID);
final String from = queryAttributes.getFirst(MoodlePluginCourseAccess.PARAM_PAGE_START);
System.out.println("************* from: " + from);
final List<MockCD> 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<String, Object> 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<String, MoodleQuizRestriction> restrcitions = new HashMap<>();
private String respondSetRestriction(final String quizId, final MultiValueMap<String, String> queryAttributes) {
final List<String> configKeys = queryAttributes.get(MoodlePluginCourseRestriction.ATTRIBUTE_CONFIG_KEYS);
final List<String> 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<String, String> 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<MockQ> getQuizzesForCourse(final int courseId) {
final String id = String.valueOf(courseId);
final Collection<MockQ> 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<String, String> queryAttributes) {
// TODO
return "";
}
}
}

View file

@ -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());
}
});
}

View file

@ -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());
}

View file

@ -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<LmsAPITemplate> 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,

View file

@ -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<LmsSetup, Lm
EntityType.LMS_SETUP,
institutionId);
final LmsSetupTestResult result = this.lmsAPIService.getLmsAPITemplate(modelId)
final LmsSetupTestResult result = this.lmsAPIService
.getLmsAPITemplate(modelId)
.map(this.lmsAPIService::test)
.getOrThrow();
.onErrorDo(error -> {
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);

View file

@ -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:<br/><br/>- Course Access: {0}<br/>- SEB Restriction: {1}
sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.<br/>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.<br/>Please consider using the origin "Moodle" LMS Setup type or install the SEB Server integration plugin on this Moodle server.<br/><br/>For further information please refer to the <a target="_blank" href="https://seb-server.readthedocs.io/en/latest/#">documentation</a>
sebserver.lmssetup.action.save=Save LMS Setup
sebserver.lmssetup.action.activate=Activate LMS Setup
sebserver.lmssetup.action.deactivate=Deactivate LMS Setup